<commit_before>%%% @doc 
%%% Block Type:  MCP9808 Temperature Sensor
%%% Description: Microchip MCP9808 precision temperature sensor with I2C interface   
%%%               
%%% @end 

-module(lblx_i2c_mcp9808).  

-author("<NAME>").

-include("../block_state.hrl"). 

%% ====================================================================
%% API functions
%% ====================================================================
-export([groups/0, description/0, version/0]).
-export([create/2, create/4, create/5, upgrade/1, initialize/1, execute/2, delete/1]).

groups() -> [sensor, input, i2c_device].

description() -> "Precision temp sensor with I2C interface".

version() -> "0.1.0".


%% Merge the block type specific, Config, Input, and Output attributes
%% with the common Config, Input, and Output attributes, that all block types have
 
-spec default_configs(BlockName :: block_name(),
                      Description :: string()) -> config_attribs().

default_configs(BlockName, Description) -> 
  attrib_utils:merge_attribute_lists(
    block_common:configs(BlockName, ?MODULE, version(), Description), 
    [
      {i2c_device, {"i2c-1"}},
      {i2c_addr, {16#18}},
      {deg_f, {true}},
      {offset, {0.0}}
    ]). 


-spec default_inputs() -> input_attribs().

default_inputs() -> 
  attrib_utils:merge_attribute_lists(
    block_common:inputs(),
    [
  
    ]). 


-spec default_outputs() -> output_attribs().
                            
default_outputs() -> 
  attrib_utils:merge_attribute_lists(
    block_common:outputs(),
    [
     
    ]). 

%%  
%% Create a set of block attributes for this block type.  
%% Init attributes are used to override the default attribute values
%% and to add attributes to the lists of default attributes
%%
-spec create(BlockName :: block_name(),
             Description :: string()) -> block_defn().

create(BlockName, Description) -> 
  create(BlockName, Description, [], [], []).

-spec create(BlockName :: block_name(),
             Description :: string(),  
             InitConfig :: config_attribs(), 
             InitInputs :: input_attribs()) -> block_defn().
   
create(BlockName, Description, InitConfig, InitInputs) -> 
  create(BlockName, Description, InitConfig, InitInputs, []).

-spec create(BlockName :: block_name(),
             Description :: string(), 
             InitConfig :: config_attribs(), 
             InitInputs :: input_attribs(), 
             InitOutputs :: list()) -> block_defn().

create(BlockName, Description, InitConfig, InitInputs, InitOutputs) ->

  % Update Default Config, Input, Output, and Private attribute values 
  % with the initial values passed into this function.
  %
  % If any of the intial attributes do not already exist in the 
  % default attribute lists, merge_attribute_lists() will create them.
    
  Config = attrib_utils:merge_attribute_lists(default_configs(BlockName, Description), InitConfig),
  Inputs = attrib_utils:merge_attribute_lists(default_inputs(), InitInputs), 
  Outputs = attrib_utils:merge_attribute_lists(default_outputs(), InitOutputs),

  % This is the block definition, 
  {Config, Inputs, Outputs}.


%%
%% Upgrade block attribute values, when block code and block data versions are different
%% 
-spec upgrade(BlockDefn :: block_defn()) -> {ok, block_defn()} | {error, atom()}.

upgrade({Config, Inputs, Outputs}) ->
  ModuleVer = version(),
  {BlockName, BlockModule, ConfigVer} = config_utils:name_module_version(Config),
  BlockType = type_utils:type_name(BlockModule),

  case attrib_utils:set_value(Config, version, version()) of
    {ok, UpdConfig} ->
      logger:info(block_type_upgraded_from_ver_to, 
                            [BlockName, BlockType, ConfigVer, ModuleVer]),
      {ok, {UpdConfig, Inputs, Outputs}};

    {error, Reason} ->
      logger:error(err_upgrading_block_type_from_ver_to, 
                            [Reason, BlockName, BlockType, ConfigVer, ModuleVer]),
      {error, Reason}
  end.


%%
%% Initialize block values
%% Perform any setup here as needed before starting execution
%%
-spec initialize(BlockState :: block_state()) -> block_state().

initialize({Config, Inputs, Outputs, Private}) ->

  Private1 = attrib_utils:add_attribute(Private, {i2c_ref, {empty}}),
  
  % Get the the I2C Address of the sensor 
  % TODO: Check for valid I2C Address
  {ok, I2cDevice} = attrib_utils:get_value(Config, i2c_device),
  {ok, I2cAddr} = attrib_utils:get_value(Config, i2c_addr),
	    
  case i2c_utils:start_link(I2cDevice, I2cAddr) of
    {ok, I2cRef} ->
      {ok, Private2} = attrib_utils:set_value(Private1, i2c_ref, I2cRef),
      
      
      {ok, DegF} = attrib_utils:get_value(Config, deg_f),
      {ok, Offset} = attrib_utils:get_value(Config, offset),
  
      % Read the ambient temperature
      case read_ambient(I2cRef, DegF, Offset) of
       {ok, Value} ->
          Status = initialed;

       {error, Reason} ->
          logger:error(err_reading_temperature_sensor, [Reason]),
          Status = proc_err,
          Value = null
       end;
      
    {error, Reason} ->
      logger:error(err_initiating_I2C_address, [Reason, I2cAddr]),
      Status = proc_err,
      Value = null,
      Private2 = Private1
  end,	
   
  Outputs1 = output_utils:set_value_status(Outputs, Value, Status),

  % This is the block state
  {Config, Inputs, Outputs1, Private2}.


%%
%%  Execute the block specific functionality
%%
-spec execute(BlockState :: block_state(), 
              ExecMethod :: exec_method()) -> block_state().

execute({Config, Inputs, Outputs, Private}, _ExecMethod) ->

  % TODO: Check flag bits?
  %  Do we need to do this? Easy to implement in block code.
  % Critical temp trips hw interrupt on chip, may need to implement that
  % if ((UpperByte & 0x80) == 0x80){ //TA > TCRIT }
  % if ((UpperByte & 0x40) == 0x40){ //TA > TUPPER }
  % if ((UpperByte & 0x20) == 0x20){ //TA < TLOWER }
  
  {ok, I2cRef} = attrib_utils:get_value(Private, i2c_ref),
  {ok, DegF} = attrib_utils:get_value(Config, deg_f),
  {ok, Offset} = attrib_utils:get_value(Config, offset),
  
  % Read the ambient temperature
  case read_ambient(I2cRef, DegF, Offset) of
    {ok, Value} ->
      Status = normal;

    {error, Reason} ->
      logger:error(err_reading_temperature_sensor, [Reason]),
      Status = proc_err,
      Value = null
   end,
   
  Outputs1 = output_utils:set_value_status(Outputs, Value, Status),

  % Return updated block state
  {Config, Inputs, Outputs1, Private}.


%% 
%%  Delete the block
%%	
-spec delete(BlockState :: block_state()) -> block_defn().

delete({Config, Inputs, Outputs, Private}) -> 
  % Close the I2C Channel
  case attrib_utils:get_value(Private, i2c_ref) of
    {ok, I2cRef} -> i2c_utils:stop(I2cRef);
    
    _ -> ok<commit_msg>Changed 'offset' attribute to 'temp_offset'<commit_after>%%% @doc 
%%% Block Type:  MCP9808 Temperature Sensor
%%% Description: Microchip MCP9808 precision temperature sensor with I2C interface   
%%%               
%%% @end 

-module(lblx_i2c_mcp9808).  

-author("<NAME>").

-include("../block_state.hrl"). 

%% ====================================================================
%% API functions
%% ====================================================================
-export([groups/0, description/0, version/0]).
-export([create/2, create/4, create/5, upgrade/1, initialize/1, execute/2, delete/1]).

groups() -> [sensor, input, i2c_device].

description() -> "Precision temp sensor with I2C interface".

version() -> "0.1.0".


%% Merge the block type specific, Config, Input, and Output attributes
%% with the common Config, Input, and Output attributes, that all block types have
 
-spec default_configs(BlockName :: block_name(),
                      Description :: string()) -> config_attribs().

default_configs(BlockName, Description) -> 
  attrib_utils:merge_attribute_lists(
    block_common:configs(BlockName, ?MODULE, version(), Description), 
    [
      {i2c_device, {"i2c-1"}},
      {i2c_addr, {16#18}},
      {deg_f, {true}},
      {temp_offset, {0.0}}
    ]). 


-spec default_inputs() -> input_attribs().

default_inputs() -> 
  attrib_utils:merge_attribute_lists(
    block_common:inputs(),
    [
  
    ]). 


-spec default_outputs() -> output_attribs().
                            
default_outputs() -> 
  attrib_utils:merge_attribute_lists(
    block_common:outputs(),
    [
     
    ]). 

%%  
%% Create a set of block attributes for this block type.  
%% Init attributes are used to override the default attribute values
%% and to add attributes to the lists of default attributes
%%
-spec create(BlockName :: block_name(),
             Description :: string()) -> block_defn().

create(BlockName, Description) -> 
  create(BlockName, Description, [], [], []).

-spec create(BlockName :: block_name(),
             Description :: string(),  
             InitConfig :: config_attribs(), 
             InitInputs :: input_attribs()) -> block_defn().
   
create(BlockName, Description, InitConfig, InitInputs) -> 
  create(BlockName, Description, InitConfig, InitInputs, []).

-spec create(BlockName :: block_name(),
             Description :: string(), 
             InitConfig :: config_attribs(), 
             InitInputs :: input_attribs(), 
             InitOutputs :: list()) -> block_defn().

create(BlockName, Description, InitConfig, InitInputs, InitOutputs) ->

  % Update Default Config, Input, Output, and Private attribute values 
  % with the initial values passed into this function.
  %
  % If any of the intial attributes do not already exist in the 
  % default attribute lists, merge_attribute_lists() will create them.
    
  Config = attrib_utils:merge_attribute_lists(default_configs(BlockName, Description), InitConfig),
  Inputs = attrib_utils:merge_attribute_lists(default_inputs(), InitInputs), 
  Outputs = attrib_utils:merge_attribute_lists(default_outputs(), InitOutputs),

  % This is the block definition, 
  {Config, Inputs, Outputs}.


%%
%% Upgrade block attribute values, when block code and block data versions are different
%% 
-spec upgrade(BlockDefn :: block_defn()) -> {ok, block_defn()} | {error, atom()}.

upgrade({Config, Inputs, Outputs}) ->
  ModuleVer = version(),
  {BlockName, BlockModule, ConfigVer} = config_utils:name_module_version(Config),
  BlockType = type_utils:type_name(BlockModule),

  case attrib_utils:set_value(Config, version, version()) of
    {ok, UpdConfig} ->
      logger:info(block_type_upgraded_from_ver_to, 
                            [BlockName, BlockType, ConfigVer, ModuleVer]),
      {ok, {UpdConfig, Inputs, Outputs}};

    {error, Reason} ->
      logger:error(err_upgrading_block_type_from_ver_to, 
                            [Reason, BlockName, BlockType, ConfigVer, ModuleVer]),
      {error, Reason}
  end.


%%
%% Initialize block values
%% Perform any setup here as needed before starting execution
%%
-spec initialize(BlockState :: block_state()) -> block_state().

initialize({Config, Inputs, Outputs, Private}) ->

  Private1 = attrib_utils:add_attribute(Private, {i2c_ref, {empty}}),
  
  % Get the the I2C Address of the sensor 
  % TODO: Check for valid I2C Address
  {ok, I2cDevice} = attrib_utils:get_value(Config, i2c_device),
  {ok, I2cAddr} = attrib_utils:get_value(Config, i2c_addr),
	    
  case i2c_utils:start_link(I2cDevice, I2cAddr) of
    {ok, I2cRef} ->
      {ok, Private2} = attrib_utils:set_value(Private1, i2c_ref, I2cRef),
      
      
      {ok, DegF} = attrib_utils:get_value(Config, deg_f),
      {ok, Offset} = attrib_utils:get_value(Config, temp_offset),
  
      % Read the ambient temperature
      case read_ambient(I2cRef, DegF, Offset) of
       {ok, Value} ->
          Status = initialed;

       {error, Reason} ->
          logger:error(err_reading_temperature_sensor, [Reason]),
          Status = proc_err,
          Value = null
       end;
      
    {error, Reason} ->
      logger:error(err_initiating_I2C_address, [Reason, I2cAddr]),
      Status = proc_err,
      Value = null,
      Private2 = Private1
  end,	
   
  Outputs1 = output_utils:set_value_status(Outputs, Value, Status),

  % This is the block state
  {Config, Inputs, Outputs1, Private2}.


%%
%%  Execute the block specific functionality
%%
-spec execute(BlockState :: block_state(), 
              ExecMethod :: exec_method()) -> block_state().

execute({Config, Inputs, Outputs, Private}, _ExecMethod) ->

  % TODO: Check flag bits?
  %  Do we need to do this? Easy to implement in block code.
  % Critical temp trips hw interrupt on chip, may need to implement that
  % if ((UpperByte & 0x80) == 0x80){ //TA > TCRIT }
  % if ((UpperByte & 0x40) == 0x40){ //TA > TUPPER }
  % if ((UpperByte & 0x20) == 0x20){ //TA < TLOWER }
  
  {ok, I2cRef} = attrib_utils:get_value(Private, i2c_ref),
  {ok, DegF} = attrib_utils:get_value(Config, deg_f),
  {ok, Offset} = attrib_utils:get_value(Config, temp_offset),
  
  % Read the ambient temperature
  case read_ambient(I2cRef, DegF, Offset) of
    {ok, Value} ->
      Status = normal;

    {error, Reason} ->
      logger:error(err_reading_temperature_sensor, [Reason]),
      Status = proc_err,
      Value = null
   end,
   
  Outputs1 = output_utils:set_value_status(Outputs, Value, Status),

  % Return updated block state
  {Config, Inputs, Outputs1, Private}.


%% 
%%  Delete the block
%%	
-spec delete(BlockState :: block_state()) -> block_defn().

delete({Config, Inputs, Outputs, Private}) -> 
  % Close the I2C Channel
  case attrib_utils:get_value(Private, i2c_ref) of
    {ok, I2cRef} -> i2c_utils:stop(I2cRef);
    
    _ -> ok
{'fraction_non_alphanumeric': 0.14608644429717987, 'fraction_numerical': 0.01340107503129372, 'mean_word_length': 3.431321370309951, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '804858', 'n_tokens_mistral': 4401, 'n_tokens_neox': 4214, 'n_words': 1065}