// TITLE    : Scilab driver for the Micos(tm) LDS 1200 Laser Diode controler
// Copyright: Samuel GOUGEON - Université du Maine / ENSIM
// Date     : 2012-
// Release  : 0.11
// License  : CeCILL
//   http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
// Software : for Scilab

function out = LDS1200(port, command, varargin)
//
// Scilab Driver for the Mikos LDS 1200 Laser Diode controler (YAG setup)
//
// Input arguments: 
// #1: Serial port number (for the open command), 
//     or serial port handle returned by "open" (for all other commands)
// #2: Command name (case unsensitive)
// #3: Data (current, temperature,..), undifferently string or numeric, case unsensitive.
//
// GENERAL CONDITIONS: 
// This function drives a LDS 1200 Laser Diode controler (by Micos(tm))
//
//  REQUIREMENTS:
//  * Scilab > 5.2.0 is required
//  * Serial TCL toolbox 0.2 (E. Segre) must be loaded
//  * OS : Windows or Linux plateform. Mac OS X are not supported (for TCL)
//  * The Laser diode controller must be connected to the chosen serial port.
//    Connexion parameters are: 9600 bauds, 8 data bits, no parity, 1 stop bit, 
//    Hardware Hand shake.
//
// SERIAL CONNEXION:
// port, 'OPEN' : Open the RS-232 communication for the given RS-232 port. 
//          If port is a string, it must follow the format "COM#:" or
//          "/dev/ttyS#" with # stating from 1 in the first case (Windows) and
//          from 0 in the second case (Linux). Else, integer numbers from 0
//          0 or N must be specified.
//          Returns 1 whether the connexion is established, 0 otherwise.
//          Remark: The LED does not switch to Remote on the device.
// port, 'CLOSE'  : Close the RS-232 communication for the given port (handle).
//          Returned 1 = OK
//
// COMMANDS, data :   Commands are case unsensitive
// --------------
// 'banner?' : returns the welcome message describing the connected device
// 'vers?'   : returns the version of the driving firmware
// 'temp?'   : returns the set temperature (only the integer part is returned)
// 'temp', T : should set the temperature to the value T (in [°C], in [5, 35]°C)
//              bug: the setting is not done.
// 'mA?'     : returns the set current (integer)
// 'mA', C   : sets the pumping diode current to C (integer, in [mA])
// 'mAmax?'  : returns the maximal value of the current (in [mA])
// 'mod?'    : returns %T (true) whether the modulation mode is on, %F otherwise.
// 'mod',0   : turns off the modulation mode
// 'mod',1   : turns on the modulation mode
// 'modShape?': returns 'tri' for triangular modulation, 'sqr' otherwise
// 'modShape', 'tri' : sets the modulation shape to triangular
// 'modShape', 'sqr' : sets the modulation shape to square. 
//             (actually, the string may be anything not containing 'tri')
// 'Fmod?'   : returns the modulation frequency   (in ~[280, 850] Hz)
// 'Fmod',F  : sets to F the modulation frequency (in ~[280, 850] Hz)
// 'modOffset?' : returns the relative modulation offset range (int. in [0,100] %)
//                Bugged (version 2.40): returns 0 (0) or 2 (1-100), instead of 0-100 
// 'modOffset',S: sets to S (integer in [0,100] %) the relative mod. offset
// 'gain?'  : returns the current value of the photodiode gain. 
//            Possible values are 1, 5, 10, 50, 100, 500
// 'gain',G : sets the photodiode gain to G. Possible values listed above.
//            If another value is asked, no action is done.
// 'gain+'  : Increases by one step the photodiode gain. 
//            Increasing gain=500 by one step leaves it unchanged
// 'gain+'  : Decreases by one step the photodiode gain. 
//            Decreasing gain=1 by one step sets leaves it unchanged

// ======================================================================

// INITIALISATIONS
// ===============
    fname = "LDS1200"    // Name of this function (for error messages)
    // ------
    out = ''         // default output value
    if  argn(2)==0 
        head_comments(fname)
        return
    end
    port  = string(port) 
	command = convstr(command,'l');
	if size(varargin)>0
        data = convstr(string(varargin(1)),'l')
        if  command=="temp"
            data = stripblanks(sprintf("%5.1f",eval(strsubst(data,',','.'))))
        end
    else data = ''
    end
    
	// Checking for the TCL serial toolbox availability:
	if ~exists('writeserial')
		tmp = _("%s: The SERIAL TCL toolbox is missing.  Please instal it before processing.\n");
		error(msprintf(tmp, fname));
	end

// =======================================================================
// MAIN COMMAND LOOP
// =======================================================================

  // OK
	if command=='open'
        if length(port)<4
            t = eval(port)
        else 
            t = port
        end
        out = openserial(t,"9600,n,8,1","binary")
        //TCL_EvalStr("fconfigure "+h+" -buffersize 30000 -sysbuffer 30000")
        return
     end

  // =====================================================================
  // OK
    if command=='close'
    	out = string(1+closeserial(port)) // Closing the port
        return
    end
  // ====================================================================
    // List of possible commands to the device
    LC = ['banner?' 'vers?' 'test?' 'temp?' 'temp' 'com' 'ma?' 'ma' 'mamax?'..
          'mod?' 'mod' 'modshape?' 'modshape' 'fmod?' 'fmod' 'fmodr?' 'fmodr' ..
          'modoffset?' 'modoffset' 'gain?' 'gain+' 'gain-' 'gain' ]
    C = struct( 'banner?', 'GX',    ..
                'vers?',    'GV',    ..
                'com',      convstr(data,'u'), ..
                'test?',    'SL',    ..
                'temp?',    'GT',    ..    // returns troncated T troncated
                'temp',     'ST '+data,  .. // Range overflowWrong parameter
                'ma?',      'GC',    ..
                'ma',       'SC '+strsubst(data,',','.'),    ..
                'mamax?',   'GU',    ..
                'mod?',     'GM',    ..  // %T | %F
                'mod',      'SM '+string(bool2s(data~='' & data~='0')),    ..
                'modshape?','GS',    ..  // 'tri' | 'sqr'
                'modshape', 'SS '+string(bool2s(strindex(data,'tri')~=[])),..
                'fmodr?','GF',    ..    // For self-call
                'fmodr', 'SF '+data, .. // For self-call. integer in [0,99]
                'modoffset?','GO',   .. // returns 0 (0-98) or 1 (99-100), INSTEAD of 0-100 (version < 2.40)
                                        // returns 0 (0) or 2 (1-100), INSTEAD of 0-100 (version 2.40)
                'modoffset', 'SO '+data,.. // integer in [0, 100]%
                'gain?',    'GG',    ..
                'gain+',    'SG 1', .. 
                'gain-',    'SG 0' .. 
                )

    if or(command==LC)
        if command=='gain' then
            gains = [1 5 10 50 100 500]
            execstr("gain="+fname+"(''"+port+"'',''gain?'')")
            gain = find(gain==gains)
            rgain = find(eval(data)==gains)
            if rgain<gain then
                for i=1:gain-rgain,
                    execstr(fname+"(''"+port+"'',''gain-'')")
                end
            elseif rgain>gain
                for i=1:rgain-gain,
                    execstr(fname+"(''"+port+"'',''gain+'')")
                end
            end
            return
        end
        if command=='gain+'    // It must not overflow 500
            execstr("g = "+fname+"(''"+port+"'',''gain?'')")
            if g==500, return, end
        end
        if command=='gain-'    // It must not underflow 1
            execstr("g = "+fname+"(''"+port+"'',''gain?'')")
            if g==1, return, end
        end

//      Frequency calibration
//      0    20    40    60    80    85    90   95   99
//      278  408   532   649   769   805   833  842  851
//      x=[0 90]  => f = 282.3 + 6.127*x
//      x=[90-99] => f = 653.4 + 1.99*x
        if command=='fmod?'
            execstr("r = "+fname+"(''"+port+"'',''fmodr?'')")
            if r<91, f = round(282.3+6.127*r)
            else f = round(653.4+1.99*r)
            end
            out = f
            return
        end
        if command=='fmod'
            data = eval(data)
            if data>=851, r = 99
            elseif data>833, r = min(round((data - 653.4)/1.99),99)
            elseif data>283, r = max(round((data - 282.3)/6.127),0)
            else r = 0
            end
            execstr(fname+"(''"+port+"'',''fmodr'',"+sprintf("%i",r)+")")
            return
        end
        // ------- else
    	tempoRead = 150      // Delay [ms] after any read operation
                             // This parameter is sensitive... DO NOT change it
        tmp = 1 + writeserial(port,C(command)+ascii([13 10]))
        sleep(tempoRead)
        if ~tmp,
            tmp = _("%s: Command ""%s"": LDS1200 controler (id %s) does not answer\n")
            error(msprintf(tmp, fname, command, port))
        else 
            tmp = ascii(readserial(port))
            sleep(tempoRead)
            out = ascii(tmp(find(tmp>31 & tmp<123)))
            if command=="mod?"
                out = (out=='1')
            elseif command=='modshape?'
                if out=='1', out = 'tri', else out = 'sqr', end
            elseif or(command==['ma?' 'temp?' 'mamax?' 'gain?' 'fmodr?'])
                out = eval(out)
            end
            return
        end
    else
        tmp = _("%s : Unknown command ""%s"" sent to the OLP device (id %s)\n")
        error(msprintf(tmp, fname, command, port))
    end

endfunction



