Skip to content

Commit

Permalink
Add support for esp:get_mac/1
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Dushin <[email protected]>
  • Loading branch information
fadushin committed Aug 7, 2023
1 parent adeba7b commit c98ebb8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 deletions.
7 changes: 7 additions & 0 deletions doc/src/programmers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,13 @@ The return type is a list of tuples, each of which contains the partition id (as
For information about the encoding of partition types and sub-types, see the IDF SDK partition [type definitions](https://docs.espressif.com/projects/esp-idf/en/v4.4.5/esp32/api-reference/storage/spi_flash.html?highlight=esp_partition_get#id13).

* `esp:get_mac/1`

The `esp:get_mac/1` function can be used to retrieve the network Media Access Control ([MAC](https://en.wikipedia.org/wiki/MAC_address)) address for a given interface, `wifi_sta` or `wifi_softap`. The return value is a 6-byte binary, in accordance with the [IEEE 802](https://en.wikipedia.org/wiki/IEEE_802) family of specifications.

%% erlang
MacAddress = esp:get_mac(wifi_sta)

## Peripherals

The AtomVM virtual machine and libraries support APIs for interfacing with peripheral devices connected to the ESP32. This section provides information about these APIs.
Expand Down
19 changes: 18 additions & 1 deletion libs/eavmlib/src/esp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
partition_list/0,
rtc_slow_get_binary/0,
rtc_slow_set_binary/1,
freq_hz/0
freq_hz/0,
get_mac/1
]).

-type esp_reset_reason() ::
Expand Down Expand Up @@ -84,6 +85,9 @@
esp_partition_props()
}.

-type interface() :: wifi_sta | wifi_softap.
-type mac() :: binary().

-define(ATOMVM_NVS_NS, atomvm).

%%-----------------------------------------------------------------------------
Expand Down Expand Up @@ -287,3 +291,16 @@ rtc_slow_set_binary(Bin) when is_binary(Bin) ->
-spec freq_hz() -> non_neg_integer().
freq_hz() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param Interface the ESP32 network interface
%% @returns The network MAC address of the specified interface
%% @doc Return the network MAC address of the specified interface.
%%
%% The mac address is returned as a 6-byte binary, per the
%% IEEE 802 family of specifications.
%% @end
%%-----------------------------------------------------------------------------
-spec get_mac(Interface :: interface()) -> mac().
get_mac(_Interface) ->
erlang:nif_error(undefined).
61 changes: 60 additions & 1 deletion src/platforms/esp32/components/avm_sys/platform_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "platform_defaultatoms.h"
#include "term.h"

#include "esp_log.h"
#include "esp_mac.h"
#include <esp_partition.h>
#include <esp_sleep.h>
#include <esp_system.h>
Expand Down Expand Up @@ -62,6 +64,8 @@
//#define ENABLE_TRACE
#include "trace.h"

#define TAG "atomvm"

#define MD5_DIGEST_LENGTH 16

static const char *const esp_rst_unknown_atom = "\xF" "esp_rst_unknown";
Expand All @@ -77,6 +81,18 @@ static const char *const esp_rst_brownout = "\x10" "esp_rst_brownout";
static const char *const esp_rst_sdio = "\xC" "esp_rst_sdio";
// 123456789ABCDEF01

enum NetworkInterface {
WifiSTAInterface,
WifiSoftAPInterface,
InvalidInterface
};

static const AtomStringIntPair interface_table[] = {
{ ATOM_STR("\x8", "wifi_sta"), WifiSTAInterface },
{ ATOM_STR("\xB", "wifi_softap"), WifiSoftAPInterface },
SELECT_INT_DEFAULT(InvalidInterface)
};

//
// NIFs
//
Expand Down Expand Up @@ -450,8 +466,42 @@ static term nif_atomvm_platform(Context *ctx, int argc, term argv[])
return ESP32_ATOM;
}

static term nif_esp_get_mac(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

GlobalContext *global = ctx->global;

int network_interface = interop_atom_term_select_int(interface_table, argv[0], global);
esp_mac_type_t interface;
switch (network_interface) {
case WifiSTAInterface:
interface = ESP_MAC_WIFI_STA;
break;
case WifiSoftAPInterface:
interface = ESP_MAC_WIFI_SOFTAP;
break;
default:
// TODO add support for BT, ETH, etc
RAISE_ERROR(BADARG_ATOM);
}

uint8_t mac[6];
esp_err_t err = esp_read_mac(mac, interface);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Unable to read mac. err=%i", err);
RAISE_ERROR(BADARG_ATOM);
}

if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(6)) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}

return term_from_literal_binary(mac, 6, &ctx->heap, ctx->global);
}

//
// NIF structures and distpatch
// NIF structures and dispatch
//

static const struct Nif esp_random_nif =
Expand Down Expand Up @@ -526,6 +576,11 @@ static const struct Nif atomvm_platform_nif =
.base.type = NIFFunctionType,
.nif_ptr = nif_atomvm_platform
};
static const struct Nif esp_get_mac_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_get_mac
};

const struct Nif *platform_nifs_get_nif(const char *nifname)
{
Expand Down Expand Up @@ -591,6 +646,10 @@ const struct Nif *platform_nifs_get_nif(const char *nifname)
TRACE("Resolved platform nif %s ...\n", nifname);
return &atomvm_platform_nif;
}
if (strcmp("esp:get_mac/1", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_get_mac_nif;
}
const struct Nif *nif = nif_collection_resolve_nif(nifname);
if (nif) {
return nif;
Expand Down

0 comments on commit c98ebb8

Please sign in to comment.