Code Monkey home page Code Monkey logo

libmodbuspp's Introduction

libmodbuspp

Much more than a C++ wrapper for the libmodbus library

Abstract

The libmodbuspp library provides a C++ overlay to libmodbus, a wrapper, having no other dependency than libmodbus and libstdc++. libmodbuspp is a free software library to send/receive data according to the MODBUS protocol. This library supports RTU (serial) and TCP (Ethernet) communications. libmodbussp allows you to implement MODBUS servers and clients. libmodbussp will be used in version 2 of the utility mbpoll. Like libmodbus, libmodbuspp is cross-platform and can be compiled on Gnu/Linux and other Unix, Windows™ and macOS™.

The Modbus::Master class allows you to design clients (also called masters), who communicate with servers (also called slaves). That is, Modbus::Master can read or write data to slaves. To do this, Modbus::Master is associated with the Modbus::Slave class which allows to perform the read and write operations, here are an example of use:

uint16_t values[2]; // array to store the values of the input registers
Master mb (Rtu, "COM1", "19200E1"); // new master on RTU
Slave & slv = mb.addSlave (33); // to the slave at address 33
mb.open(); // open a connection
slv.readInputRegisters (1, values, 2);
cout << values[0] << endl;
cout << values[1] << endl;

This example reads the input registers number 1 and 2 of the MODBUS slave (server) at address 33. The source code of this program is searchable in the examples folder read-input-registers

The Modbus::Server class is used to design servers. An object of the class Modbus::Server allows to implement one or more slaves that can be dissociated by the use of a different address. The Modbus::Server class is associated with the Modbus::BufferedSlave class to implement slaves. Modbus::BufferedSlave used by Modbus::Server is derived from Modbus::Slave used by Modbus::Master, it allows to define data blocks corresponding to each MODBUS entity: input registers, discrete inputs, holding registers and coils.

Here is an example of use:

// ModBus Data
bool daylight;// daylight saving time, true = summer time
Data<int32_t> gmtoff; // GMT offset, +/- minutes
uint16_t mb_time[8]; // date and time
Server srv (Tcp, "127.0.0.1", "1502"); // new Modbus Server on TCP/IP
BufferedSlave & slv = srv.addSlave (10); // Adding a new slave to the server
// defines the data blocks of our slave slv
slv.setBlock (InputRegister, 8); // date and time
slv.setBlock (HoldingRegister, 2); // GMT offset, +/- minutes
slv.setBlock (Coil, 1); // daylight saving time, ON = summer time
//...
slv.writeCoil (1, daylight);
slv.writeRegister (1, gmtoff);
if (srv.open ()) { // open a connection
  for (;;) {
    now = time (nullptr);
    if (now > before) {
      before = now;
      // update daylight saving time from holding register
      slv.readCoil (1, daylight);
      // update GMT offset from holding register
      slv.readRegister (1, gmtoff);
      // calculate the epoch time
      now += (daylight ? 3600 : 0) + gmtoff;
      t = gmtime (&now);
      mb_time[0] = t->tm_sec;
      mb_time[1] = t->tm_min;
      mb_time[2] = t->tm_hour;
      mb_time[3] = t->tm_mday;
      mb_time[4] = t->tm_mon + 1;
      mb_time[5] = t->tm_year + 1900;
      mb_time[6] = t->tm_wday;
      mb_time[7] = t->tm_yday + 1;
      // update the input registers
      slv.writeInputRegisters (1, mb_time, 8);
    }
    srv.poll (100);
  }
}

This example realizes a MODBUS time server which has the slave address 10. The source code of this program is searchable in the examples folder clock-server.

As can be seen in this example libmodbuspp also has a template class Modbus::Data that allows to easily manage registers of a size greater than or equal to 16 bits. This class allows you to manipulate all arithmetic types int, long, float, double... in the form of MODBUS registers in a transparent manner for the user. The default storage order of bytes and words is the big Indian but can be chosen when declaring the variable using enumeration Modbus::Endian, for example:

Data<float,EndianBigLittle> voltage;

allows to define a floating number (32-bit) with a byte order in big Endian and a word organization in little Endian (CDAB).

A Modbus::BufferedSlave object is also able to relay the requests it receives to:

  • "real" slaves connected by RTU (or TCP) to the machine running the server (Modbus::Server).
  • callback functions that the user of the library can define in order to to perform a custom processing of requests.

The processing of messages by the callback functions is simplified thanks to the Modbus::Request and Modbus::Response classes (derived from the Modbus::Message class).

The Server class is used to intercept received messages.
The installation of the callback function is performed by Server::setMessageCallback().
The function thus installed will be called if the slave address (unit identifier) does not correspond to any slave registered by Server::addSlave().
This will make it possible to process MODBUS messages not supported by libmodbus or, to route the messages to links not supported by libmodbus.
Here is an example of a callback function:

int messageHandler (Message * req, Device * dev) {
  cout << "Receive message, size : " << req->aduSize() << endl;
  if (req->function() == ReadInputRegisters) {
    // the dummy word will be the returned value, incremented after each reading
    static uint16_t dummy = 1; 
    // get request parameters
    uint16_t N = req->quantity();
    uint16_t index = req->startingAddress();
    // build response, see page 16 of MODBUS Application Protocol Specification
    Response rsp (*req); // uses copy constructor to keep transaction id
    rsp.setSize(1); // keep until function code
    rsp.setByteCount (N * 2);
    for (uint16_t i = 0; i < N; i++) {
      rsp.setRegisterValue (index + i, dummy++);
    }
    return dev->sendRawMessage (rsp, true);
  }
  return 0;
}

The virtual-server example illustrates this functionality.

The Modbus::Router class performs a MODBUS message routing using the additional address which is a byte which precedes the byte of the function code. This additional address is also called "Unit Identifier" in MODBUS-TCP and address fields or slave address in MODBUS-OSL.

A Router object is in permanent listening on its link from the outside, it is seen by the remote client as a server which groups all the slaves connected on the link or links from the inside.

As the Router class is derived from the Server class, it also makes it possible to create slaves consisting only of primary tables (discrete inputs, input registers, etc.) in memory.

Whether outside or inside, the links can be over TCP-IP or serial link (RTU).

The connection from the outside is configured either with setBackend() or with setConfig() (or the corresponding variants of the Router constructor).

Inside bindings are added using addMaster() methods. This makes sense because these links control slaves. As the MODBUS masters do not have an address on the bus, they are identified by a name.

Here is a diagram showing an example of use:

Router example

The routing elements are BufferedSlave which are added using addSlave(). The master parameter indicates the route to take to communicate with this slave. If this parameter is zero, the slave is made up only of primary tables. The slaves are naturally identified by the identifiers (additional address).

All this can be described in a JSON file, which allows you to simply modify the routing structure without having to recompile.

The json file below corresponds to the description of a router listening on TCP-IP (port 1502 of localhost). It has two routing links to a hardware serial link (/dev/ttyUSB0) where slave 33 is located (SolarPi pressure sensor) and a virtual serial link (/dev/tnt0) where slave 10 is located (clock-server-json):

{
  "modbuspp-router": {
    "mode": "tcp",
    "connection": "localhost",
    "settings": "1502",
    "recovery-link": true,
    "debug": true,
    "response-timeout": 500,
    "byte-timeout": 500,
    "masters": [
      {
        "name": "rs232",
        "mode": "rtu",
        "connection": "/dev/ttyUSB0",
        "settings": "38400E1",
        "debug": true,
        "response-timeout": 500,
        "byte-timeout": 500,
        "slaves": [
          {
            "id": 33,
            "blocks": [
              {
                "table": "input-register",
                "quantity": 6
              },
              {
                "table": "holding-register",
                "quantity": 8
              }
            ]
          }
        ]
      },
      {
        "name": "virtual-clock",
        "mode": "rtu",
        "connection": "/dev/tnt0",
        "settings": "38400E1",
        "debug": true,
        "response-timeout": 3000,
        "byte-timeout": 500,
        "slaves": [
          {
            "id": 10,
            "blocks": [
              {
                "table": "input-register",
                "quantity": 8
              },
              {
                "table": "holding-register",
                "quantity": 2
              },
              {
                "table": "coil",
                "quantity": 1
              }
            ]
          }
        ]
      }
    ]
  }
}

The program to perform this routing is very simple :

string  jsonfile = argv[1];
Router router (jsonfile, "modbuspp-router");

if (router.open ()) {

  router.run();
  while (router.isOpen()) {

    std::this_thread::sleep_for (std::chrono::milliseconds (200));
  }
}

How beautiful is that ? :-)

The source code of this program is searchable in the examples folder router-json.

Note on routing libmodbus in RTU

libmodbus does not support routing in RTU, in fact, only messages intended for a single slave (that of the context) or broadcast are processed.
The author of libmodbus, Stéphane, justifies this choice in his terms:
"Filter on the Modbus unit identifier (slave) in RTU mode to avoid useless CRC computing."
To benefit from the routing capacity of the Router and Server classes in RTU, you must therefore use the fork of libmodbus named libmodbusepsi.
In this fork released from the piduino repository, filtering can be disabled (with modbus_rtu_set_recv_filter()).
Thus, it is the Server class which performs this filtering (after checking the CRC therefore). Effectively, this has the effect of loading the microprocessor, but, at present, the computing power of our machines is such that it does not pose a problem.

Quickstart guide

libmodbuspp comes with full documentation in manual and html format.

Installation

The fastest and safest way to install libmodbuspp on Debian, Armbian, Raspbian ... is to use the APT repository from piduino.org, so you should do the following :

wget -O- http://www.piduino.org/piduino-key.asc | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.piduino.org stretch piduino'
sudo apt update
sudo apt install libmodbuspp-dev libmodbuspp-doc 

This repository provides Piduino packages for i386, amd64, armhf and arm64 architectures.
In the above commands, the repository is a Debian Stretch distribution, but you can also choose Buster, Ubuntu Xenial or Bionic by replacing stretch with bsuter, xenial or bionic. It may be necessary to install the software-properties-common package for add-apt-repository.

For Raspbian you have to do a little different :

wget -O- http://www.piduino.org/piduino-key.asc | sudo apt-key add -
echo 'deb http://raspbian.piduino.org stretch piduino' | sudo tee /etc/apt/sources.list.d/piduino.list
sudo apt update
sudo apt install libmodbuspp-dev libmodbuspp-doc

The Raspbian repository provides Piduino packages for armhf architecture for Stretch only.

If you want to build from sources, you can follow the Wiki.

How To build an example ?

Here is a complete example that can be compiled without error:

#include <iostream>
#include <string>
#include <modbuspp.h>

using namespace std;
using namespace Modbus;

int main (int argc, char **argv) {
  string port ("/dev/ttyUSB0");

  Master mb (Rtu, port , "38400E1"); // new master on RTU
  Slave & slv = mb.addSlave (33); // to the slave at address 33

  if (mb.open ()) { // open a connection
    // success, do what you want here
    uint16_t values[2];

    if (slv.readInputRegisters (1, values, 2) == 2) {

      cout << "R0=" << values[0] << endl;
      cout << "R1=" << values[1] << endl;
    }
    else {
      cerr << "Unable to read input registers !"  << endl;
      exit (EXIT_FAILURE);
    }
    mb.close();
  }
  else {
    cerr << "Unable to open MODBUS connection to " << port << endl;
    exit (EXIT_FAILURE);
  }

  return 0;
}

Enter the text of this program with your favorite text editor and save the file in main.cpp

To build, you must type the command:

g++ -o read-input-registers main.cpp $(pkg-config --cflags --libs modbuspp)

You can then run it :

./read-input-registers 
R0=9964
R1=10029

With Codelite it's easier and funny, right ?

Debugging with Codelite

You will find several examples in the folder /usr/share/doc/modbuspp/examples

Documentation

The libmodbuspp-doc package provides documentation.

The classes provided by the library are documented by man pages:

  • The Modbus_Master page for the Modbus::Master class
  • The Modbus_Slave page for the Modbus::Slave class
  • The Modbus_Server page for the Modbus::Server class
  • The Modbus_Router page for the Modbus::Router class
  • The Modbus_BufferedSlave page for the Modbus::BufferedSlave class
  • The Modbus_Data page for the Modbus::Data class
  • The Modbus_Request page for the Modbus::Request class
  • The Modbus_Response page for the Modbus::Response class
  • The Modbus_RtuLayer page for the Modbus::RtuLayer class
  • The Modbus_TcpLayer page for the Modbus::TcpLayer class
  • The Modbus_Timeout page for the Modbus::Timeout class

The complete API is documented in the folder /usr/share/doc/modbuspp/api-manual

About Modbus

MODBUS is considered an application layer messaging protocol, providing Master/Slave communication between devices connected together through buses or networks. On the OSI model, MODBUS is positioned at level 7. MODBUS is intended to be a request/reply protocol and delivers services specified by function codes. The function codes of MODBUS are elements of MODBUS’ request/reply PDUs (Protocol Data Unit).

In order to build the MODBUS application data unit, the client must initiate a MODBUS transaction. It is the function which informs the server as to which type of action to perform. The format of a request initiated by a Master is established by the MODBUS application protocol. The function code field is then coded into one byte. Only codes within the range of 1 through 255 are considered valid, with 128-255 being reserved for exception responses. When the Master sends a message to the Slave, it is the function code field which informs the server of what type of action to perform.

To define multiple actions, some functions will have sub-function codes added to them. For instance, the Master is able to read the ON/OFF states of a group of discreet outputs or inputs. It could also read/write the data contents of a group of MODBUS registers. When the Master receives the Slave response, the function code field is used by the Slave to indicate either an error-free response or an exception response. The Slave echoes to the request of the initial function code in the case of a normal response.

libmodbuspp's People

Contributors

de-vri-es avatar epsilonrt avatar northpower avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

libmodbuspp's Issues

Bug report

Hi
I will first thank you for your work on this library. I have used it on Tcp at this works perfectly. My problem is in Rtu that is not possible to set parity to 'N' none. I look through your files and found that you are not looking to see if the parity is 'N'.

An easy fix will set p='N' instead of 'E'.

  char RtuLayer::parity (const std::string & settings) {
    char p = 'E';
    size_t s = settings.length();

    if (s >= 2) {
      char c = settings[s - 2];
      if ( (c == 'E') || (c == 'O')) {
        return c;
      }
    }
    return p;
  }

char RtuLayer::parity (const std::string & settings) {
char p = 'E';
size_t s = settings.length();
if (s >= 2) {
char c = settings[s - 2];
if ( (c == 'E') || (c == 'O')) {
return c;
}
}
return p;
}

I have made a pull request with the little change.
Thanks again for your work on this Modbus library. Have a great day

Possibility of having RTU over TCP client connection to a Modbus slave

Hello! First of all, thanks for your great work on libmodbuspp! The nice docs and examples made it very easy to get up and running to develop my first modbus application. Now I specifically need to implement a TCP client connection to a gateway with many RTU slave devices connected to it, so I need to establish a RTU over TCP client connection. From what I understood from the "virtual-rtu" branch and the "Server" and "Router" examples in the master branch it seems it only works for inbound connections. It seems though there is underlying support for RTU over TCP implemented. Is it possible to simply adapt it so we can have a "RTU-TCP" backend as well when instantiating the Modbus Master?

Cross compilation error

Hi,
currently, I am trying to use this library in a project on the Rpi. If I want to cross-compile my project, an error occurs with CMake. It says that certain files in "/usr/" are not present. If I change
if(NOT EXISTS "${file}" )
to
if(NOT EXISTS "${SYSROOT_PATH}/${file}" )
in line 63 in the generated modbuspp.cmake file, everything works fine. Would it be possible to change the CMakeLists.txt in a way that this is defined by default?

Problem compiling on MacOS

Hi,

I was trying to compile libmodbuspp on MacOS (since I could not find it as a package for homebrew).

I got the below error messages:

[  7%] Building CXX object lib/CMakeFiles/objlib.dir/__/src/request.cpp.o
warning: unknown warning option '-Wno-psabi' [-Wunknown-warning-option]
In file included from /Users/kraft/Code/libmodbuspp/src/request.cpp:17:
/Users/kraft/Code/libmodbuspp/include/modbuspp/device.h:105:80: error: implicit instantiation of undefined template 'std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >'
      explicit Device (const std::string & jsonfile, const std::string & key = std::string());
                                                                               ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/iosfwd:209:32: note: template is declared here
    class _LIBCPP_TEMPLATE_VIS basic_string;
                               ^
In file included from /Users/kraft/Code/libmodbuspp/src/request.cpp:17:
/Users/kraft/Code/libmodbuspp/include/modbuspp/device.h:189:79: error: implicit instantiation of undefined template 'std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >'
      bool setConfig (const std::string & jsonfile, const std::string & key = std::string());
                                                                              ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/iosfwd:209:32: note: template is declared here
    class _LIBCPP_TEMPLATE_VIS basic_string;
                               ^
In file included from /Users/kraft/Code/libmodbuspp/src/request.cpp:19:
In file included from /Users/kraft/Code/libmodbuspp/include/modbuspp/request.h:19:
In file included from /Users/kraft/Code/libmodbuspp/include/modbuspp/message.h:24:
/Users/kraft/Code/libmodbuspp/include/modbuspp/data.h:283:17: warning: enumeration values 'Uint16' and 'Int16' not handled in switch [-Wswitch]
        switch (m_value) {
                ^
/Users/kraft/Code/libmodbuspp/include/modbuspp/data.h:283:17: note: add missing switch cases
        switch (m_value) {
                ^
2 warnings and 2 errors generated.

Full cmake logfile and full build output attached.
cmake .. &> cmake.log
make -k &> full-build.txt

cmake.log
full-build.txt

RtuLayer::parity and RtuLayer::stop

Hi,

how the following function could parse "19200N1"?

  // ---------------------------------------------------------------------------
  // static
  char RtuLayer::parity (const std::string & settings) {
    char p = 'E';
    size_t s = settings.length();

    if (s >= 2) {
      char c = settings[s - 2];
      if ( (c == 'E') || (c == 'O')) {
        return c;
      }
    }
    return p;
  }

and stop bit could be 1 or 2 independent of N

  // ---------------------------------------------------------------------------
  // static
  int RtuLayer::stop (const std::string & settings) {

    if (parity (settings) == 'N') {

      return 2;
    }
    return 1;
  }

How to compile on windows for MS visual

Hello,
ia ma one of the old programmers still on win7 and would like to use the libraray for MS Visual 17. I have no Linux and have no clue running it. Is there a windows repository or how do i compile the library on windows for visual ?
Salut

modbus.h

I keep getting a fault saying "modbus.h: No such file or directory". I can figure out that i have not linked something correctly but i am having a really hard time figuring out how to link the different libraries. I have also thought that it might be because my libmodbus is not in the correct location, but again i can not read from the documentation where it is supposed to be. Hope u can help me.

SOVERSION is too long

The version of the shared library is in the M.m-B format (e.g., 0.3-48) which makes it necessary to recompile all libmodbuspp-dependent programs with each update. It should be limited to the major number.

Reading 2 registers with nb=1 when calling readRegisters function

I'm reading through RTU mode as master at 38400 8N1
Master: Raspberrypi, connected to system running modpoll simulator in slave mode using FTDI cable

I'm able to read registers using the aforementioned function, But the modpoll simulator receives a request for reading two consecutive registers from the starting address.The value received from the simulator is in accordance with the same.

When I tried reading from the libmodbus (C) directly using modbus_read_registers, the response is as desired: reading 1 register at a time

Please help me in resolving this issue

complation issue

Dear Sir
I am using debian, and during compilation this error cropped up:

libmodbuspp/include/modbuspp/data.h:374:20: error: 'out_of_range' is not a member of 'std'
374 | throw std::out_of_range (str);

My os info is as follows: gcc version 10.2.1 20210110 (Debian 10.2.1-6)
i fixed it by including the header file stdexcept to the data.h file, and thereafter the compilation had no further issues.

Regards.
Stoffels

Many dependencies

I get the following output when installing:

debian@beaglebone:~$ sudo apt install libmodbuspp-dev libmodbuspp-doc
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  bzip2 git git-man libcurl3-gnutls libdpkg-perl liberror-perl
  libfile-fcntllock-perl libmodbusepsi-dev libmodbusepsi5 libmodbuspp
  pkg-config xz-utils
Suggested packages:
  bzip2-doc gettext-base git-daemon-run | git-daemon-sysvinit git-doc git-el
  git-email git-gui gitk gitweb git-cvs git-mediawiki git-svn debian-keyring
  gcc | c-compiler binutils bzr dpkg-dev
The following NEW packages will be installed:
  bzip2 git git-man libcurl3-gnutls libdpkg-perl liberror-perl
  libfile-fcntllock-perl libmodbusepsi-dev libmodbusepsi5 libmodbuspp
  libmodbuspp-dev libmodbuspp-doc pkg-config xz-utils
0 upgraded, 14 newly installed, 0 to remove and 62 not upgraded.
Need to get 9543 kB of archives.
After this operation, 36.8 MB of additional disk space will be used.
Do you want to continue? [Y/n]

Are all these really needed?

How to include externally using CMake

Hello, thanks for the repository!

Is there a clean way to include it from other projects, using find_package(Modbus) or something similar, instead of hard-coding the paths? (I installed it using apt)

If yes, could this info be added to the README ?

[BUG] Byte order mismatch

When I start a server with this config, and read registers out like that:

Modbus::Data<float, Modbus::EndianBigLittle> values[4];  // is cdab order

if (slave->readRegisters (1, values, 4) > 0)  
... 

Then I get wrong data.
Only if I use EndianLittleBig, I get correct results.

Invalid CRC when reading from Holding Registers

I was trying to fetch data from the modbus simulator we have, but the response which i am getting with the example cpp program for reading from holding registers says

Unable to read input registers ! Invalid CRC

The same simulator i tested with other wrappers around libmodbus they were able to interpret the values and display the result.
I am also attaching the diagnostics msgs from the simulator

Tx-> 01 03 04 00 00 40 40 CA 03
Rx-> 01 03 00 F8 00 02 45 FA

Multiple connection to Server or Router

Hi,

how can I make multiple connections to the server/router in the same time? I try to connect two masters (QModMaster installed on two computers) but only first connection is able to collect data. From the source or example I am not able to find what to do.
Testing environment:
Ubuntu 18.04 where the sources are installed and compiled
Windows 10 for master part (QModMaster )
Thank in advance.

Boris

Modbus Rtu crc invaild

Hi
Is there a way to cout the received message from the slave? I am getting an invalid CRC error and I will like to see if there is a CRC error or if it something else. I have tried using Qmodbus master simulator at which works fine so the slave unit that I am using works. I have uses your library before with Tcp at it works perfectly. Thank you for your work on this library.

Implementing TCP Server with multiple available connections.

Hello! Thank you for this great solution!

I need to implement TCP server with multiple available connections.

In libmodbus we can do this by creating listening socket, then catching incoming connection to handle requests and listen socket again for new connection.

Is there any way to do this with modbuspp? I cant find any appropriate methods in modbuspp rather than Modbus::Server::open().

Thank you in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.