This is the open source Pawn interpreter ported to mbed. See here: http://www.compuphase.com/pawn/pawn.htm and here: http://code.google.com/p/pawnscript/

Dependents:   Pawn4Test

Some instructions:

  • Put the attached include folder next to your source, so when you compile you get all the proper definitions
  • Use the attached main.p as a starting point if you wish
  • Compile your main.p into main.amx - Put your main.amx on the mbed 'drive'
  • Reset and be amazed.

Important Compile Notes:

  • You should use the -S# option to define a smaller default stack size. Start with -S64 and go up from there if needed.
  • To use on the Cortex-M0 version of the mbed (LPC11U24), you MUST include the TARGET=3 command-line option as well, so the pin names are properly defined. In the future this may be handled on the native code side.

Known Issues:

  • At the moment it appears the kbhit() function is not working right - at least on my mac. Will continue testing on Windows. Working fine.

Todo:

  • Add more wrappers for the mbed peripherals
  • Add Pawn overlay support, to allow much larger scripts to run (even on the LPC11U24)
Revision:
0:3ab1d2d14eb3
Child:
2:01588bd27169
diff -r 000000000000 -r 3ab1d2d14eb3 amxtime.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/amxtime.c	Thu Nov 15 17:41:21 2012 +0000
@@ -0,0 +1,453 @@
+/*  Date/time module for the Pawn Abstract Machine
+ *
+ *  Copyright (c) ITB CompuPhase, 2001-2011
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ *  use this file except in compliance with the License. You may obtain a copy
+ *  of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *  License for the specific language governing permissions and limitations
+ *  under the License.
+ *
+ *  Version: $Id: amxtime.c 4541 2011-07-21 12:15:13Z thiadmer $
+ */
+#include <time.h>
+#include <assert.h>
+#include "osdefs.h"
+#include "amx.h"
+#if defined __WIN32__ || defined _WIN32 || defined _Windows
+  #include <windows.h>
+  #include <mmsystem.h>
+#endif
+
+#define CELLMIN   (-1 << (8*sizeof(cell) - 1))
+
+#define SECONDS_PER_MINUTE	60
+#define SECONDS_PER_HOUR	3600
+#define SECONDS_PER_DAY		86400
+#define SECONDS_PER_YEAR	31556952	/* based on 365.2425 days per year */
+
+#if !defined CLOCKS_PER_SEC
+  #define CLOCKS_PER_SEC CLK_TCK
+#endif
+#if defined __WIN32__ || defined _WIN32 || defined WIN32
+  static int timerset = 0;
+  /* timeGetTime() is more accurate on WindowsNT if timeBeginPeriod(1) is set */
+  #define INIT_TIMER()    \
+    if (!timerset) {      \
+      timeBeginPeriod(1); \
+      timerset=1;         \
+    }
+#else
+  #define INIT_TIMER()
+#endif
+static unsigned long timestamp;
+static unsigned long timelimit;
+static int timerepeat;
+
+static const unsigned char monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static int wrap(int value, int min, int max)
+{
+  if (value<min)
+    value=max;
+  else if (value>max)
+    value=min;
+  return value;
+}
+
+static unsigned long gettimestamp(void)
+{
+  unsigned long value;
+
+  #if defined __WIN32__ || defined _WIN32 || defined WIN32
+    value=timeGetTime();        /* this value is already in milliseconds */
+  #elif defined __linux || defined __linux__ || defined __LINUX__
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    value = ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+  #else
+    value=clock();
+    #if CLOCKS_PER_SEC<1000
+      /* convert to milliseconds */
+      value=(cell)((1000L * value) / CLOCKS_PER_SEC);
+    #elif CLOCKS_PER_SEC>1000
+      /* convert to milliseconds */
+      value=(cell)(value/(CLOCKS_PER_SEC/1000));
+    #endif
+  #endif
+  return value;
+}
+
+void stamp2datetime(unsigned long sec1970,
+                    int *year, int *month, int *day,
+                    int *hour, int *minute, int *second)
+{
+  int days, seconds;
+
+  /* find the year */
+  assert(year!=NULL);
+  for (*year = 1970; ; *year += 1) {
+    days = 365 + ((*year & 0x03) == 0); /* clumsy "leap-year" routine, fails for 2100 */
+    seconds = days * SECONDS_PER_DAY;
+    if ((unsigned long)seconds > sec1970)
+      break;
+    sec1970 -= seconds;
+  } /* if */
+
+  /* find the month */
+  assert(month!=NULL);
+  for (*month = 1; ; *month += 1) {
+    days = monthdays[*month - 1];
+    seconds = days * SECONDS_PER_DAY;
+    if ((unsigned long)seconds > sec1970)
+      break;
+    sec1970 -= seconds;
+  } /* if */
+
+  /* find the day */
+  assert(day!=NULL);
+  for (*day = 1; sec1970 >= SECONDS_PER_DAY; *day += 1)
+    sec1970 -= SECONDS_PER_DAY;
+
+  /* find the hour */
+  assert(hour!=NULL);
+  for (*hour = 0; sec1970 >= SECONDS_PER_HOUR; *hour += 1)
+    sec1970 -= SECONDS_PER_HOUR;
+
+  /* find the minute */
+  assert(minute!=NULL);
+  for (*minute = 0; sec1970 >= SECONDS_PER_MINUTE; *minute += 1)
+    sec1970 -= SECONDS_PER_MINUTE;
+
+  /* remainder is the number of seconds */
+  assert(second!=NULL);
+  *second = (int)sec1970;
+}
+
+static void settime(cell hour,cell minute,cell second)
+{
+  #if defined __WIN32__ || defined _WIN32 || defined WIN32
+    SYSTEMTIME systim;
+
+    GetLocalTime(&systim);
+    if (hour!=CELLMIN)
+      systim.wHour=(WORD)wrap((int)hour,0,23);
+    if (minute!=CELLMIN)
+      systim.wMinute=(WORD)wrap((int)minute,0,59);
+    if (second!=CELLMIN)
+      systim.wSecond=(WORD)wrap((int)second,0,59);
+    SetLocalTime(&systim);
+  #else
+    /* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
+     * must have "root" permission to call stime()
+     */
+    time_t sec1970;
+    struct tm gtm;
+
+    time(&sec1970);
+    gtm=*localtime(&sec1970);
+    if (hour!=CELLMIN)
+      gtm.tm_hour=wrap((int)hour,0,23);
+    if (minute!=CELLMIN)
+      gtm.tm_min=wrap((int)minute,0,59);
+    if (second!=CELLMIN)
+      gtm.tm_sec=wrap((int)second,0,59);
+    sec1970=mktime(&gtm);
+    stime(&sec1970);
+  #endif
+}
+
+static void setdate(cell year,cell month,cell day)
+{
+  int maxday;
+
+  #if defined __WIN32__ || defined _WIN32 || defined WIN32
+    SYSTEMTIME systim;
+
+    GetLocalTime(&systim);
+    if (year!=CELLMIN)
+      systim.wYear=(WORD)wrap((int)year,1970,2099);
+    if (month!=CELLMIN)
+      systim.wMonth=(WORD)wrap((int)month,1,12);
+    maxday=monthdays[systim.wMonth - 1];
+    if (systim.wMonth==2 && ((systim.wYear % 4)==0 && ((systim.wYear % 100)!=0 || (systim.wYear % 400)==0)))
+      maxday++;
+    if (day!=CELLMIN)
+      systim.wDay=(WORD)wrap((int)day,1,maxday);
+    SetLocalTime(&systim);
+  #else
+    /* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
+     * must have "root" permission to call stime()
+     */
+    time_t sec1970;
+    struct tm gtm;
+
+    time(&sec1970);
+    gtm=*localtime(&sec1970);
+    if (year!=CELLMIN)
+      gtm.tm_year=year-1900;
+    if (month!=CELLMIN)
+      gtm.tm_mon=month-1;
+    if (day!=CELLMIN)
+      gtm.tm_mday=day;
+    sec1970=mktime(&gtm);
+    stime(&sec1970);
+  #endif
+}
+
+
+/* settime(hour, minute, second)
+ * Always returns 0
+ */
+static cell AMX_NATIVE_CALL n_settime(AMX *amx, const cell *params)
+{
+  (void)amx;
+  settime(params[1],params[2],params[3]);
+  return 0;
+}
+
+/* gettime(&hour, &minute, &second)
+ * The return value is the number of seconds since 1 January 1970 (Unix system
+ * time).
+ */
+static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
+{
+  time_t sec1970;
+  struct tm gtm;
+  cell *cptr;
+
+  assert(params[0]==(int)(3*sizeof(cell)));
+
+  time(&sec1970);
+
+  /* on DOS/Windows, the timezone is usually not set for the C run-time
+   * library; in that case gmtime() and localtime() return the same value
+   */
+  gtm=*localtime(&sec1970);
+  cptr=amx_Address(amx,params[1]);
+  *cptr=gtm.tm_hour;
+  cptr=amx_Address(amx,params[2]);
+  *cptr=gtm.tm_min;
+  cptr=amx_Address(amx,params[3]);
+  *cptr=gtm.tm_sec;
+
+  /* the time() function returns the number of seconds since January 1 1970
+   * in Universal Coordinated Time (the successor to Greenwich Mean Time)
+   */
+  return (cell)sec1970;
+}
+
+/* setdate(year, month, day)
+ * Always returns 0
+ */
+static cell AMX_NATIVE_CALL n_setdate(AMX *amx, const cell *params)
+{
+  (void)amx;
+  setdate(params[1],params[2],params[3]);
+  return 0;
+}
+
+/* getdate(&year, &month, &day)
+ * The return value is the number of days since the start of the year. January
+ * 1 is day 1 of the year.
+ */
+static cell AMX_NATIVE_CALL n_getdate(AMX *amx, const cell *params)
+{
+  time_t sec1970;
+  struct tm gtm;
+  cell *cptr;
+
+  assert(params[0]==(int)(3*sizeof(cell)));
+
+  time(&sec1970);
+
+  gtm=*localtime(&sec1970);
+  cptr=amx_Address(amx,params[1]);
+  *cptr=gtm.tm_year+1900;
+  cptr=amx_Address(amx,params[2]);
+  *cptr=gtm.tm_mon+1;
+  cptr=amx_Address(amx,params[3]);
+  *cptr=gtm.tm_mday;
+
+  return gtm.tm_yday+1;
+}
+
+/* tickcount(&granularity)
+ * Returns the number of milliseconds since start-up. For a 32-bit cell, this
+ * count overflows after approximately 24 days of continuous operation.
+ */
+static cell AMX_NATIVE_CALL n_tickcount(AMX *amx, const cell *params)
+{
+  cell *cptr;
+
+  assert(params[0]==(int)sizeof(cell));
+
+  INIT_TIMER();
+  cptr=amx_Address(amx,params[1]);
+  #if defined __WIN32__ || defined _WIN32 || defined WIN32
+    *cptr=1000;               	/* granularity = 1 ms */
+  #else
+    *cptr=(cell)CLOCKS_PER_SEC;	/* in Unix/Linux, this is often 100 */
+  #endif
+  return gettimestamp() & 0x7fffffff;
+}
+
+/* delay(milliseconds)
+ * Pauses for (at least) the requested number of milliseconds.
+ */
+static cell AMX_NATIVE_CALL n_delay(AMX *amx, const cell *params)
+{
+  unsigned long stamp;
+
+  (void)amx;
+  assert(params[0]==(int)sizeof(cell));
+
+  INIT_TIMER();
+  stamp=gettimestamp();
+  while (gettimestamp()-stamp < (unsigned long)params[1])
+    /* nothing */;
+  return 0;
+}
+
+/* settimer(milliseconds, bool: singleshot = false)
+ * Sets the delay until the @timer() callback is called. The timer may either
+ * be single-shot or repetitive.
+ */
+static cell AMX_NATIVE_CALL n_settimer(AMX *amx, const cell *params)
+{
+  (void)amx;
+  assert(params[0]==(int)(2*sizeof(cell)));
+  timestamp=gettimestamp();
+  timelimit=params[1];
+  timerepeat=(int)(params[2]==0);
+  return 0;
+}
+
+/* bool: gettimer(&milliseconds, bool: &singleshot = false)
+ * Retrieves the timer set with settimer(); returns true if a timer
+ * was set up, or false otherwise.
+ */
+static cell AMX_NATIVE_CALL n_gettimer(AMX *amx, const cell *params)
+{
+  cell *cptr;
+
+  assert(params[0]==(int)(2*sizeof(cell)));
+  cptr=amx_Address(amx,params[1]);
+  *cptr=timelimit;
+  cptr=amx_Address(amx,params[2]);
+  *cptr=timerepeat;
+  return timelimit>0;
+}
+
+/* settimestamp(seconds1970) sets the date and time from a single parameter: the
+ * number of seconds since 1 January 1970.
+ */
+static cell AMX_NATIVE_CALL n_settimestamp(AMX *amx, const cell *params)
+{
+  #if defined __WIN32__ || defined _WIN32 || defined WIN32
+    int year, month, day, hour, minute, second;
+
+    stamp2datetime(params[1],
+                   &year, &month, &day,
+                   &hour, &minute, &second);
+    setdate(year, month, day);
+    settime(hour, minute, second);
+  #else
+    /* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
+     * must have "root" permission to call stime()
+     */
+    time_t sec1970=(time_t)params[1];
+    stime(&sec1970);
+  #endif
+  (void)amx;
+
+  return 0;
+}
+
+/* cvttimestamp(seconds1970, &year, &month, &day, &hour, &minute, &second)
+ */
+static cell AMX_NATIVE_CALL n_cvttimestamp(AMX *amx, const cell *params)
+{
+  int year, month, day, hour, minute, second;
+
+  (void)amx;
+  stamp2datetime(params[1],
+                 &year, &month, &day,
+                 &hour, &minute, &second);
+  return 0;
+}
+
+
+#if !defined AMXTIME_NOIDLE
+static AMX_IDLE PrevIdle = NULL;
+static int idxTimer = -1;
+
+static int AMXAPI amx_TimeIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
+{
+  int err=0;
+
+  assert(idxTimer >= 0);
+
+  if (PrevIdle != NULL)
+    PrevIdle(amx, Exec);
+
+  if (timelimit>0 && (gettimestamp()-timestamp)>=timelimit) {
+    if (timerepeat)
+      timestamp+=timelimit;
+    else
+      timelimit=0;      /* do not repeat single-shot timer */
+    err = Exec(amx, NULL, idxTimer);
+    while (err == AMX_ERR_SLEEP)
+      err = Exec(amx, NULL, AMX_EXEC_CONT);
+  } /* if */
+
+  return err;
+}
+#endif
+
+
+#if defined __cplusplus
+  extern "C"
+#endif
+const AMX_NATIVE_INFO time_Natives[] = {
+  { "gettime",      n_gettime },
+  { "settime",      n_settime },
+  { "getdate",      n_getdate },
+  { "setdate",      n_setdate },
+  { "tickcount",    n_tickcount },
+  { "settimer",     n_settimer },
+  { "gettimer",     n_gettimer },
+  { "delay",        n_delay },
+  { "settimestamp", n_settimestamp },
+  { "cvttimestamp", n_cvttimestamp },
+  { NULL, NULL }        /* terminator */
+};
+
+int AMXEXPORT AMXAPI amx_TimeInit(AMX *amx)
+{
+  #if !defined AMXTIME_NOIDLE
+    /* see whether there is a @timer() function */
+    if (amx_FindPublic(amx,"@timer",&idxTimer) == AMX_ERR_NONE) {
+      if (amx_GetUserData(amx, AMX_USERTAG('I','d','l','e'), (void**)&PrevIdle) != AMX_ERR_NONE)
+        PrevIdle = NULL;
+      amx_SetUserData(amx, AMX_USERTAG('I','d','l','e'), amx_TimeIdle);
+    } /* if */
+  #endif
+
+  return amx_Register(amx, time_Natives, -1);
+}
+
+int AMXEXPORT AMXAPI amx_TimeCleanup(AMX *amx)
+{
+  (void)amx;
+  #if !defined AMXTIME_NOIDLE
+    PrevIdle = NULL;
+  #endif
+  return AMX_ERR_NONE;
+}