branch feature/7459 updated (a13af77 -> ed81d11)
This is an automated email from the git hooks/post-receive script. New change to branch feature/7459 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git from a13af77 ajout de la connexion au pied à coulisse depuis l'appli (refs #7459) new 0241863 lecture des données reçues sur le pied à coulisse (refs #7459) new 4670088 modif de la conif de port série : nombre au lieu de faire une liste des ports dispo (refs #7459) new ed81d11 affichage du port série écouté dans la barre de statut (refs #7459) The 3 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit ed81d117c0eeec51edff67a2ac9c0856816b0f15 Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:30:12 2016 +0200 affichage du port série écouté dans la barre de statut (refs #7459) commit 46700889b43e745daad22cf975cc772900835dee Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:28:40 2016 +0200 modif de la conif de port série : nombre au lieu de faire une liste des ports dispo (refs #7459) commit 0241863f218e54054e29ad62a9bf6b5acbbf1da9 Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:27:04 2016 +0200 lecture des données reçues sur le pied à coulisse (refs #7459) Summary of changes: tutti-caliper/pom.xml | 69 +---------- .../fr/ifremer/tutti/caliper/feed/Caliper.java | 135 --------------------- .../caliper/feed/CaliperConnectionException.java | 24 ++++ .../tutti/caliper/feed/CaliperFeedReader.java | 19 +-- .../record/CaliperFeedReaderMeasureRecord.java | 15 ++- .../record/CaliperFeedReaderRecordFactory.java | 8 +- .../java/fr/ifremer/tutti/TuttiConfiguration.java | 5 +- .../fr/ifremer/tutti/TuttiConfigurationOption.java | 5 +- .../java/fr/ifremer/tutti/util/SerialPort.java | 12 -- .../i18n/tutti-persistence_en_GB.properties | 1 + .../fr/ifremer/tutti/ui/swing/content/MainUI.jcss | 3 +- .../content/actions/ConnectCaliperAction.java | 2 +- 12 files changed, 61 insertions(+), 237 deletions(-) delete mode 100644 tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/Caliper.java delete mode 100644 tutti-persistence/src/main/java/fr/ifremer/tutti/util/SerialPort.java -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/7459 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit 0241863f218e54054e29ad62a9bf6b5acbbf1da9 Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:27:04 2016 +0200 lecture des données reçues sur le pied à coulisse (refs #7459) --- tutti-caliper/pom.xml | 69 +---------- .../fr/ifremer/tutti/caliper/feed/Caliper.java | 135 --------------------- .../caliper/feed/CaliperConnectionException.java | 24 ++++ .../tutti/caliper/feed/CaliperFeedReader.java | 19 +-- .../record/CaliperFeedReaderMeasureRecord.java | 15 ++- .../record/CaliperFeedReaderRecordFactory.java | 8 +- 6 files changed, 53 insertions(+), 217 deletions(-) diff --git a/tutti-caliper/pom.xml b/tutti-caliper/pom.xml index 8c4fced..36a564f 100644 --- a/tutti-caliper/pom.xml +++ b/tutti-caliper/pom.xml @@ -75,6 +75,7 @@ <scope>test</scope> </dependency> + <!-- Serial port reading --> <dependency> <groupId>com.neuronrobotics</groupId> <artifactId>nrjavaserial</artifactId> @@ -84,72 +85,4 @@ </dependencies> - <profiles> - <profile> - <id>tools</id> - <activation> - <property> - <name>performRelease</name> - <value>true</value> - </property> - </activation> - - <properties> - <redmine.releaseFiles> - target/${project.build.finalName}-tools.zip - </redmine.releaseFiles> - </properties> - - <build> - <defaultGoal>package</defaultGoal> - - <plugins> - <plugin> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <id>jar</id> - <goals> - <goal>assembly</goal> - </goals> - <phase>package</phase> - <configuration> - <descriptorRefs> - <descriptorRef>jar-with-dependencies</descriptorRef> - </descriptorRefs> - - </configuration> - </execution> - <execution> - <id>zip</id> - <goals> - <goal>assembly</goal> - </goals> - <phase>package</phase> - <configuration> - <descriptor>src/main/assembly/tools.xml</descriptor> - </configuration> - </execution> - </executions> - <configuration> - <finalName>${project.build.finalName}-tools</finalName> - <appendAssemblyId>false</appendAssemblyId> - </configuration> - </plugin> - </plugins> - </build> - - - <dependencies> - - <dependency> - <groupId>log4j</groupId> - <artifactId>log4j</artifactId> - <scope>runtime</scope> - </dependency> - - </dependencies> - </profile> - </profiles> - </project> diff --git a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/Caliper.java b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/Caliper.java deleted file mode 100644 index b63acb5..0000000 --- a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/Caliper.java +++ /dev/null @@ -1,135 +0,0 @@ -package fr.ifremer.tutti.caliper.feed; - -import gnu.io.CommPort; -import gnu.io.CommPortIdentifier; -import gnu.io.SerialPort; -import gnu.io.SerialPortEvent; -import gnu.io.SerialPortEventListener; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * @author Kevin Morin (Code Lutin) - * @since x.x - */ -public class Caliper { - public Caliper() - { - super(); - } - - void connect ( String portName ) throws Exception - { - CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); - if ( portIdentifier.isCurrentlyOwned() ) - { - System.out.println("Error: Port is currently in use"); - } - else - { - CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000); - - if ( commPort instanceof SerialPort ) - { - SerialPort serialPort = (SerialPort) commPort; - serialPort.setSerialPortParams(4800,SerialPort.DATABITS_7,SerialPort.STOPBITS_1,SerialPort.PARITY_EVEN); - - InputStream in = serialPort.getInputStream(); - OutputStream out = serialPort.getOutputStream(); - - (new Thread(new SerialWriter(out))).start(); - - serialPort.addEventListener(new SerialReader(in)); - serialPort.notifyOnDataAvailable(true); - - } - else - { - System.out.println("Error: Only serial ports are handled by this example."); - } - } - } - - /** - * Handles the input coming from the serial port. A new line character - * is treated as the end of a block in this example. - */ - public static class SerialReader implements SerialPortEventListener - { - private InputStream in; - private byte[] buffer = new byte[1024]; - - public SerialReader ( InputStream in ) - { - this.in = in; - } - - public void serialEvent(SerialPortEvent arg0) { - int data; - - try - { - int len = 0; - while ( ( data = in.read()) > -1 ) - { - if ( data == '\n' ) { - break; - } - buffer[len++] = (byte) data; - } - System.out.print(new String(buffer,0,len)); - } - catch ( IOException e ) - { - e.printStackTrace(); - System.exit(-1); - } - } - - } - - /** */ - public static class SerialWriter implements Runnable - { - OutputStream out; - - public SerialWriter ( OutputStream out ) - { - this.out = out; - } - - public void run () - { - try - { - int c = 0; - while ( ( c = System.in.read()) > -1 ) - { - this.out.write(c); - } - } - catch ( IOException e ) - { - e.printStackTrace(); - System.exit(-1); - } - } - } - - - - public static void main ( String[] args ) - { - try - { - (new Caliper()).connect("COM1"); - } - catch ( Exception e ) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} diff --git a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperConnectionException.java b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperConnectionException.java index fb9a0f6..c188300 100644 --- a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperConnectionException.java +++ b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperConnectionException.java @@ -1,5 +1,29 @@ package fr.ifremer.tutti.caliper.feed; +/* + * #%L + * Tutti :: Caliper API + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2016 Ifremer + * %% + * 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 3 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, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + /** * @author Kevin Morin (Code Lutin) * @since 4.5 diff --git a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperFeedReader.java b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperFeedReader.java index 6dbec27..27b837b 100644 --- a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperFeedReader.java +++ b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/CaliperFeedReader.java @@ -22,7 +22,6 @@ package fr.ifremer.tutti.caliper.feed; * #L% */ -import com.google.common.base.Preconditions; import fr.ifremer.tutti.caliper.feed.event.CaliperFeedReaderEvent; import fr.ifremer.tutti.caliper.feed.event.CaliperFeedReaderListener; import fr.ifremer.tutti.caliper.feed.record.CaliperFeedReaderMeasureRecord; @@ -35,7 +34,6 @@ import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,6 +54,13 @@ public class CaliperFeedReader implements Closeable { /** Logger. */ private static final Log log = LogFactory.getLog(CaliperFeedReader.class); + private static final String SERIAL_PORT_PREFIX = "COM"; + + /** + * Name of the serial port + */ + protected String serialPortName; + /** * Serial port open in the {@code start} method. */ @@ -78,12 +83,12 @@ public class CaliperFeedReader implements Closeable { recordFactory = new CaliperFeedReaderRecordFactory(); } - public void start(String portName) throws CaliperConnectionException { + public void start(int portNumber) throws CaliperConnectionException { - Preconditions.checkArgument(StringUtils.isNotEmpty(portName), "serial port can not be null or empty"); + this.serialPortName = SERIAL_PORT_PREFIX + portNumber; try { - CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); + CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortName); serialPort = portIdentifier.open(this.getClass().getName(), 2000); serialPort.setSerialPortParams(4800, SerialPort.DATABITS_7, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN); @@ -99,7 +104,7 @@ public class CaliperFeedReader implements Closeable { } catch (IOException | TooManyListenersException | PortInUseException | NoSuchPortException | UnsupportedCommOperationException e) { if (log.isErrorEnabled()) { - log.error("Error while connecting to the serial port " + portName, e); + log.error("Error while connecting to the serial port " + serialPortName, e); } throw new CaliperConnectionException(e); } @@ -131,7 +136,7 @@ public class CaliperFeedReader implements Closeable { } public String getSerialPortName() { - return serialPort != null ? serialPort.getName() : null; + return serialPortName; } /** diff --git a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderMeasureRecord.java b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderMeasureRecord.java index 5fbb8dd..49a1f6e 100644 --- a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderMeasureRecord.java +++ b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderMeasureRecord.java @@ -25,7 +25,9 @@ package fr.ifremer.tutti.caliper.feed.record; */ import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.math.NumberUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * A measure record. @@ -39,9 +41,13 @@ public class CaliperFeedReaderMeasureRecord extends CaliperFeedReaderRecordSuppo private static final long serialVersionUID = 1L; + /** Received values are like +12,345\n */ + private static final Pattern RECORD_PATTERN = Pattern.compile("\\+(\\w+),\\w+\\s*"); + public static boolean acceptRecord(String record) { - return NumberUtils.isNumber(record); + Matcher matcher = RECORD_PATTERN.matcher(record); + return matcher.matches(); } @@ -49,7 +55,10 @@ public class CaliperFeedReaderMeasureRecord extends CaliperFeedReaderRecordSuppo CaliperFeedReaderMeasureRecord(String record) { super(record); - measure = Integer.valueOf(record); + Matcher matcher = RECORD_PATTERN.matcher(record); + matcher.find(); + String intPart = matcher.group(1); + measure = Integer.valueOf(intPart); } public int getMeasure() { diff --git a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderRecordFactory.java b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderRecordFactory.java index a6fea28..a9c4c01 100644 --- a/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderRecordFactory.java +++ b/tutti-caliper/src/main/java/fr/ifremer/tutti/caliper/feed/record/CaliperFeedReaderRecordFactory.java @@ -33,11 +33,11 @@ import java.util.Set; */ public class CaliperFeedReaderRecordFactory { - protected final Set<CaliperFeedReaderRecordAceptor> acceptors; + protected final Set<CaliperFeedReaderRecordAcceptor> acceptors; public CaliperFeedReaderRecordFactory() { acceptors = new LinkedHashSet<>(); - acceptors.add(new CaliperFeedReaderRecordAceptor<CaliperFeedReaderMeasureRecord>() { + acceptors.add(new CaliperFeedReaderRecordAcceptor<CaliperFeedReaderMeasureRecord>() { @Override public boolean accept(String record) { return CaliperFeedReaderMeasureRecord.acceptRecord(record); @@ -55,7 +55,7 @@ public class CaliperFeedReaderRecordFactory { CaliperFeedReaderRecordSupport feedRecord = null; - for (CaliperFeedReaderRecordAceptor acceptor : acceptors) { + for (CaliperFeedReaderRecordAcceptor acceptor : acceptors) { boolean accept = acceptor.accept(record); if (accept) { @@ -71,7 +71,7 @@ public class CaliperFeedReaderRecordFactory { } - protected static interface CaliperFeedReaderRecordAceptor<F extends CaliperFeedReaderRecordSupport> { + protected interface CaliperFeedReaderRecordAcceptor<F extends CaliperFeedReaderRecordSupport> { boolean accept(String record); -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/7459 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit 46700889b43e745daad22cf975cc772900835dee Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:28:40 2016 +0200 modif de la conif de port série : nombre au lieu de faire une liste des ports dispo (refs #7459) --- .../src/main/java/fr/ifremer/tutti/TuttiConfiguration.java | 5 ++--- .../main/java/fr/ifremer/tutti/TuttiConfigurationOption.java | 5 ++--- .../src/main/java/fr/ifremer/tutti/util/SerialPort.java | 12 ------------ .../main/resources/i18n/tutti-persistence_en_GB.properties | 1 + 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfiguration.java b/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfiguration.java index 613b18c..ab5397e 100644 --- a/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfiguration.java +++ b/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfiguration.java @@ -29,7 +29,6 @@ import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel; import fr.ifremer.tutti.type.CoordinateEditorType; import fr.ifremer.tutti.type.WeightUnit; import fr.ifremer.tutti.util.BeepFrequency; -import fr.ifremer.tutti.util.SerialPort; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.logging.Log; @@ -733,8 +732,8 @@ public class TuttiConfiguration extends ApplicationConfiguration { return applicationConfig.getOptionAsInt(TuttiConfigurationOption.ICHTYOMETER_MAXIMUM_NUMBER_OF_ATTEMPT_TO_CONNECT.getKey()); } - public SerialPort getCaliperSerialPort() { - return SerialPort.valueOf(applicationConfig.getOption(TuttiConfigurationOption.CALIPER_SERIAL_PORT.getKey())); + public int getCaliperSerialPort() { + return applicationConfig.getOptionAsInt(TuttiConfigurationOption.CALIPER_SERIAL_PORT.getKey()); } public Boolean isExternalDevicesVoiceEnabled() { diff --git a/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfigurationOption.java b/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfigurationOption.java index 97c0413..2177eb6 100644 --- a/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfigurationOption.java +++ b/tutti-persistence/src/main/java/fr/ifremer/tutti/TuttiConfigurationOption.java @@ -26,7 +26,6 @@ import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel; import fr.ifremer.tutti.type.CoordinateEditorType; import fr.ifremer.tutti.type.WeightUnit; import fr.ifremer.tutti.util.BeepFrequency; -import fr.ifremer.tutti.util.SerialPort; import org.hibernate.dialect.HSQLDialect; import org.hsqldb.jdbcDriver; import org.nuiton.config.ConfigOptionDef; @@ -650,8 +649,8 @@ public enum TuttiConfigurationOption implements ConfigOptionDef { CALIPER_SERIAL_PORT( "tutti.ichtyometer.caliperSerialPort", n("tutti.config.option.caliper.serialPort.description"), - "COM1", - SerialPort.class, + "1", + int.class, false ), EXTERNAL_DEVICES_VOICE_ENABLED( diff --git a/tutti-persistence/src/main/java/fr/ifremer/tutti/util/SerialPort.java b/tutti-persistence/src/main/java/fr/ifremer/tutti/util/SerialPort.java deleted file mode 100644 index 6cd4ba7..0000000 --- a/tutti-persistence/src/main/java/fr/ifremer/tutti/util/SerialPort.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.ifremer.tutti.util; - -/** - * @author Kevin Morin (Code Lutin) - * @since 4.5 - */ -public enum SerialPort { - - COM1, - COM2, - COM3 -} diff --git a/tutti-persistence/src/main/resources/i18n/tutti-persistence_en_GB.properties b/tutti-persistence/src/main/resources/i18n/tutti-persistence_en_GB.properties index e9fd0bc..7dd397c 100644 --- a/tutti-persistence/src/main/resources/i18n/tutti-persistence_en_GB.properties +++ b/tutti-persistence/src/main/resources/i18n/tutti-persistence_en_GB.properties @@ -10,6 +10,7 @@ tutti.caracteristicType.vesselUseFeature= tutti.config= tutti.config.option.basedir.description= tutti.config.option.beepFrequency.description= +tutti.config.option.caliper.serialPort.description= tutti.config.option.cruiseId.description= tutti.config.option.csv.separator.description= tutti.config.option.data.directory.description= -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/7459 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit ed81d117c0eeec51edff67a2ac9c0856816b0f15 Author: Kevin Morin <morin@codelutin.com> Date: Thu Apr 21 10:30:12 2016 +0200 affichage du port série écouté dans la barre de statut (refs #7459) --- .../src/main/java/fr/ifremer/tutti/ui/swing/content/MainUI.jcss | 3 ++- .../ifremer/tutti/ui/swing/content/actions/ConnectCaliperAction.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/MainUI.jcss b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/MainUI.jcss index ce1cee1..0041ff7 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/MainUI.jcss +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/MainUI.jcss @@ -340,7 +340,8 @@ JMenu { actionIcon: "bluetooth-up"; disabledIcon: {jaxx.runtime.SwingUtil.createActionIcon("bluetooth-down")}; enabled: {model.isCaliperConnected()}; - toolTipText: {handler.getCaliperStatusLabel(model.isCaliperConnected())}; + toolTipText: {handler.getCaliperStatusTip(model.isCaliperConnected())}; + text: {handler.getCaliperStatusLabel(model.isCaliperConnected())}; _help: {"tutti.main.status.caliper.help"}; } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/ConnectCaliperAction.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/ConnectCaliperAction.java index ddd0584..e0ea92c 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/ConnectCaliperAction.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/ConnectCaliperAction.java @@ -45,7 +45,7 @@ public class ConnectCaliperAction extends AbstractMainUITuttiAction { public void doAction() throws Exception { CaliperFeedReader caliperReader = new CaliperFeedReader(); - caliperReader.start(getConfig().getCaliperSerialPort().name()); + caliperReader.start(getConfig().getCaliperSerialPort()); getContext().setCaliperReader(caliperReader); } -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
participants (1)
-
codelutin.com scm