/*
 * rcx.nqh - version 2.0
 * Copyright (C) 1998,1999 Dave Baum
 *
 * CyberMaster definitions by Laurentino Martins
 *
 * This file is part of nqc, the Not Quite C compiler for the RCX
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * The Initial Developer of this code is David Baum.
 * Portions created by David Baum are Copyright (C) 1998 David Baum.
 * All Rights Reserved.
 *
 * Portions created by John Hansen are Copyright (C) 2005 John Hansen.
 * All Rights Reserved.
 *
 */

/*
 *  This file defines various system constants and macros to be used
 *  with the RCX.  Most of the real functionality of the RCX is
 *  defined here rather than within nqcc itself.
 *
 */


// this is a copy of the NQC 1.3 rcx.nqh file

/**************************
 * input
 **************************/

// constants for selecting sensors
#define IN_1    Input(0)
#define IN_2    Input(1)
#define IN_3    Input(2)

#ifdef __CM
// alternative names for input sensors
#define IN_L IN_1 // Left sensor
#define IN_M IN_2 // Middle sensor
#define IN_R IN_3 // Right sensor
#endif

// modes for SensorMode() and IN_CFG()
#define SMODE_RAW       0x00
#define SMODE_BOOL      0x20
#define SMODE_EDGE      0x40
#define SMODE_PULSE     0x60
#define SMODE_PERCENT   0x80
#ifdef __RCX
#define SMODE_CELSIUS   0xa0
#define SMODE_FAHRENHEIT 0xc0
#define SMODE_ANGLE     0xe0
#endif

#define SensorMode(sensor, mode)    asm { 0x42, $sensor : 0x03000200, (mode) }

#ifdef __RCX
// types for SensorType() and IN_CFG()
#define STYPE_SWITCH    1
#define STYPE_TEMP      2
#define STYPE_LIGHT     3
#define STYPE_ANGLE     4

// input configurations - used in calls to Sensor()
#define IN_CFG(type,mode)   (((type)<<8) + (mode))
#define IN_SWITCH   IN_CFG(STYPE_SWITCH, SMODE_BOOL)
#define IN_PULSE    IN_CFG(STYPE_SWITCH, SMODE_PULSE)
#define IN_EDGE     IN_CFG(STYPE_SWITCH, SMODE_EDGE)
#define IN_LIGHT    IN_CFG(STYPE_LIGHT,  SMODE_PERCENT)
#define IN_ANGLE    IN_CFG(STYPE_ANGLE,  SMODE_ANGLE)

// set a sensor's type
#define SensorType(sensor, type)    asm { 0x32, $sensor : 0x03000200, (type) }

// set a sensor's type and mode using a config - e.g. Sensor(IN_1, IN_LIGHT);
#define Sensor(sensor, tm)  do { SensorType(sensor, tm>>8); \
                                     SensorMode(sensor, tm); } while (false)

#endif



/**************************
 * output
 **************************/

// constants for selecting outputs
#define OUT_A   (1 << 0)
#define OUT_B   (1 << 1)
#define OUT_C   (1 << 2)

// output modes
#define OUT_FLOAT   0
#define OUT_OFF     0x40
#define OUT_ON      0x80

// output directions
#define OUT_REV     0
#define OUT_FLIP    0x40
#define OUT_FWD     0x80

// speeds
#define OUT_LOW     1
#define OUT_HALF    4
#define OUT_FULL    7

// output functions
#define OutputMode(o, m)    asm { 0x21, (o) + (m) }
#define OutputDir(o, d)     asm { 0xe1, (o) + (d) }
#define OutputPower(o, p)   asm { 0x13, (o), $p : 0x1000015}

#define Fwd(o, p)   do {    OutputDir(o,OUT_FWD); \
                            OutputMode(o,OUT_ON); \
                            OutputPower(o,p); } while(false)

#define Rev(o, p)   do {    OutputDir(o,OUT_REV); \
                            OutputMode(o,OUT_ON); \
                            OutputPower(o,p); } while(false)

#define Off(o)              OutputMode(o, OUT_OFF)
#define Float(o)            OutputMode(o, OUT_FLOAT)
#define Toggle(o)           OutputDir((o), OUT_FLIP)


// CyberMaster specific stuff
#ifdef __CM
// alternate names for motors
#define OUT_L OUT_A // Left motor
#define OUT_R OUT_B // Right motor
#define OUT_X OUT_C // External motor

#define Drive(m0, m1)                     asm { 0x41, DIRSPEED(m0) | DIRSPEED(m1)<<4 }
#define OnWait(m, n, t)                   asm { 0xc2, (m)<<4 | DIRSPEED(n), t }
#define OnWaitDifferent(m, n0, n1, n2, t) asm { 0x53, (m)<<4 | DIRSPEED(n0), DIRSPEED(n1)<<4 | DIRSPEED(n2), t }

// Aux. function: Transforms a number between -7 and 7 to a 4 bit sequence:
// Bits: 1..3 - Speed: 0 to 7
// Bit : 4    - Direction: 1 if v>=0, 0 if v<0
#define DIRSPEED(v)     ((v)&8^8|((v)*(((v)>>3)*2^1))&7)


#endif



/**************************
 * data sources
 **************************/

#define Timer(n)        @(0x10000 + (n))
#define Random(n)       @(0x40000 + (n))
#define Input(n)        @(0x90000 + (n))
#define InputType(n)    @(0xa0000 + (n))
#define InputMode(n)    @(0xb0000 + (n))

#ifdef __RCX
// RCX specific data sources
#define Program()       @(0x8)
#define InputRaw(n)     @(0xc0000 + (n))
#define InputBool(n)    @(0xd0000 + (n))
#define Watch()         @(0xe0000)
#define Message()       @(0xf0000)
#endif

#ifdef __CM
// CM specific data sources
#define TachoCount(n)          @(0x50000 + (n)-1) // Use OUT_x as parameter
#define TachoSpeed(n)          @(0x60000 + (n)-1) // Use OUT_x as parameter
#define ExternalMotorRunning() @(0x70002)         // Referred in the SDK as MotorCurrent(2). Non zero if external motor running.
#define AGC()                  @(0x100000)        // Automatic Gain Control
#endif


/**************************
 * miscellaneous
 **************************/

// wait for a condition to become true
#define wait(c)     while(!(c))

// playing sounds and notes
#define PlaySound(x)        asm { 0x51, x }
#define PlayNote(f, d)      asm { 0x23, (f), (f)>>8, (d) }

// sleep for v ticks (10ms per tick)
#define Sleep(v)    asm { 0x43, $v : 0x0015}


#define ClearTimer(n)   asm { 0xa1, n }
#define ClearSensor(sensor) asm { 0xd1, $sensor : 0x03000200 }

#define StopAllTasks()  asm { 0x50 }

#ifdef __RCX
// set the display mode
#define Display(v)  asm { 0x33, $v : 0x0005}

// IR message support
#define SendMessage(v)  asm { 0xb2, $v : 0x1000005 }
#define ClearMessage()  asm { 0x90 }

// Data logging
#define SetDatalog(size)    asm { 0x52, (size), (size)>>8 }
#define Datalog(v)          asm { 0x62, $v : 0x1004203}
#define UploadDatalog(s, n) asm { 0xa4, (s), (s)>>8, (n), (n)>>8 }

// set the system clock
#define SetWatch(h, m)      asm { 0x22, (h), (m) }

// support for controlling the IRMode
#define IR_LO 0
#define IR_HI 1
#define IRMode(m)      asm { 0x31, m }
#endif

#ifdef __CM
#define ClearTachoCounter(m) asm { 0x11, (m) }
#endif

#pragma noinit
