diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 58800872e6824eb799d7081944bfac346a138ac4..682bccb74600611c1ab79fe3e3c98ebd1c97f929 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -176,6 +176,9 @@ namespace Common {
 
   Type *Type::get_stream_type(MessageEncodingType_t encoding_type, int stream_variant)
   {
+    if (stream_variant == 0) {
+      return get_pooltype(T_BSTR);
+    }
     switch (encoding_type) {
     case CT_BER:
     case CT_PER:
@@ -184,13 +187,11 @@ namespace Common {
     case CT_JSON:
       return get_pooltype(T_OSTR);
     case CT_TEXT:
-      if(stream_variant==0){
+      if(stream_variant==1){
         return get_pooltype(T_CSTR);
       } else {
         return get_pooltype(T_OSTR);
       }
-    case CT_CUSTOM:
-      return get_pooltype(T_BSTR);
     default:
       FATAL_ERROR("Type::get_stream_type()");
       return 0;
@@ -606,6 +607,8 @@ namespace Common {
     chk_finished = false;
     pard_type_instance = false;
     needs_any_from_done = false;
+    encoding_by_function = false;
+    decoding_by_function = false;
     asn_encoding = CT_UNDEF;
     asn_decoding = CT_UNDEF;
   }
@@ -4395,27 +4398,45 @@ namespace Common {
   
   void Type::set_coding_function(bool encode, const string& function_name)
   {
-    string& coding_str = encode ? encoding_str : decoding_str;
-    if (!coding_str.empty()) {
-      error("Multiple custom %s functions declared for type '%s' (function `%s' "
-        "is already set)", encode ? "encoding" : "decoding",
-        get_typename().c_str(), coding_str.c_str());
+    string& coding_function = encode ? encoding_function : decoding_function;
+    MessageEncodingType_t& asn_coding = encode ? asn_encoding : asn_decoding;
+    bool& coding_by_function = encode ?
+      encoding_by_function : decoding_by_function;
+    if (!coding_function.empty()) {
+      // leave coding_by_function as true, this will indicate that there are
+      // multiple coding functions set
+      coding_function.clear();
+    }
+    else if (asn_coding != CT_UNDEF) {
+      // a different encoding type is already set for the ASN.1 type
+      asn_coding = CT_MULTIPLE;
+      coding_function.clear();
       return;
     }
-    coding_str = function_name;
-    coding_by_function = true;
+    else {
+      if (is_asn1()) {
+        asn_coding = CT_PER;
+      }
+      coding_function = function_name;
+      coding_by_function = true;
+    }
   }
   
   void Type::set_asn_coding(bool encode, Type::MessageEncodingType_t new_coding)
   {
     MessageEncodingType_t& coding = encode ? asn_encoding : asn_decoding;
-    if (coding == CT_UNDEF) {
+    bool& coding_by_function = encode ?
+      encoding_by_function : decoding_by_function; // true = PER coder is set
+    string& coding_function = encode ? encoding_function : decoding_function; // PER coder
+    if (coding == CT_UNDEF && !coding_by_function) {
       // this is the first encoding/decoding function for this type, store it
+      // (also, no PER coders have been set for the type yet)
       coding = new_coding;
     }
-    else if (coding != new_coding) {
+    else if (coding != new_coding || coding_by_function) {
       // there are several encoding/decoding functions declared for this type
       // with different codings (encvalue/decvalue cannot be used in this case)
+      coding_function.clear();
       coding = CT_MULTIPLE;
     }
   }
@@ -4424,7 +4445,8 @@ namespace Common {
     string& coding_str = encode ? encoding_str : decoding_str;
     if (!coding_str.empty())
       return;
-    coding_by_function = false;
+    bool& coding_by_function = encode ?
+      encoding_by_function : decoding_by_function;
     Type::MessageEncodingType_t coding = CT_UNDEF;
 
     if (!is_asn1()) {
@@ -4517,18 +4539,18 @@ namespace Common {
     else { // ASN.1 type
       coding = encode ? asn_encoding : asn_decoding;
       if ((coding == CT_UNDEF && delayed) || coding == CT_MULTIPLE) {
-        // either this is the delayed call and no external function has been
+        // either this is the delayed call and no external functions have been
         // found, or there was already more than one function
         error("Cannot determine the %s rules for ASN.1 type `%s'. "
-          "%s %s external function%s found%s", encode ? "encoding" : "decoding",
+          "%s %s external functions found%s", encode ? "encoding" : "decoding",
           get_typename().c_str(), coding == CT_UNDEF ? "No" : "Multiple",
-          encode ? "encoding" : "decoding", coding == CT_UNDEF ? "" : "s",
+          encode ? "encoding" : "decoding",
           coding == CT_UNDEF ? "" : " with different rules");
         return;
       }
-      if (coding == CT_UNDEF && !delayed) {
-        // the coding type is set by the external function's checker in this case;
-        // it's possible, that the function exists, but has not been reached yet;
+      if (!delayed) {
+        // there have been no errors so far in determining the coding type,
+        // but there might still be unchecked external functions out there;
         // delay this function until everything else has been checked
         Modules::delay_type_encode_check(this, encode);
         return;
@@ -4547,9 +4569,6 @@ namespace Common {
       case CT_TEXT:
         coding_str = "TEXT";
         break;
-      case CT_PER:
-        coding_str = "PER";
-        break;
       case CT_XER:
         coding_str = "XER, XER_EXTENDED"; // TODO: fine tuning this parameter
         break;
@@ -4568,20 +4587,31 @@ namespace Common {
         if (!berattrib)
           delete ber;
         break; }
-      case CT_CUSTOM:
-        if (!delayed) {
-          // coding_str is set by the coding function's checker in this case;
-          // it's possible, that the function exists, but has not been reached yet;
+      case CT_PER:
+      case CT_CUSTOM: {
+        // the coding function is set by its semantic checker in this case
+        string& coding_function = encode ? encoding_function : decoding_function;
+        if (coding_function.empty() && coding_by_function) {
+          error("Multiple %s %s functions set for type `%s'",
+            get_encoding_name(coding), encode ? "encoding" : "decoding",
+            get_typename().c_str());
+        }
+        else if (!delayed) {
+          // there have been no errors so far in determining the coding function,
+          // but there might still be unchecked external functions out there;
           // delay this function until everything else has been checked
           Modules::delay_type_encode_check(this, encode);
         }        
-        else if (coding_str.empty()) {
-          // this is the delayed call, and the custom coding function has still
-          // not been found
-          error("No custom %s function found for type `%s'",
+        else if (coding_function.empty()) {
+          // this is the delayed call, and the coding function has still not been set
+          error("No %s %s function found for type `%s'", get_encoding_name(coding),
             encode ? "encoding" : "decoding", get_typename().c_str());
         }
-        return;
+        else {
+          // this is the delayed call, and exactly one coding function has been set
+          coding_str = coding_function;
+        }
+        return; }
       default:
         error("Unknown coding selected for type '%s'", get_typename().c_str());
         break;
@@ -4589,8 +4619,8 @@ namespace Common {
     coding_by_function = false;
   }
 
-  bool Type::is_coding_by_function() const {
-    return coding_by_function;
+  bool Type::is_coding_by_function(bool encode) const {
+    return encode ? encoding_by_function : decoding_by_function;
   }
 
   const string& Type::get_coding(bool encode) const {
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index 4c811023c13711363b909b538a3431dee2064e03..c1e442cc4ef96eeeaa3b239ef39dab592df1cbdf 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -307,7 +307,10 @@ namespace Common {
 
     string encoding_str;  // needed by codegen for encvalue() and decvalue()
     string decoding_str;
-    bool coding_by_function;  // false - coding attribute is set, true - coding via coding function
+    bool encoding_by_function;  // false - coding attribute is set, true - coding via coding function
+    bool decoding_by_function;  // same for decoding
+    string encoding_function; // name of custom or PER encoder
+    string decoding_function; // name of custom or PER decoder
     MessageEncodingType_t asn_encoding; // set by the semantic analysis of encoding
     MessageEncodingType_t asn_decoding; // and decoding external functions for ASN.1 types
     /** What kind of AST element owns the type.
@@ -659,7 +662,7 @@ namespace Common {
     void set_coding_function(bool encode, const string& function_name);
     void set_asn_coding(bool encode, MessageEncodingType_t new_coding);
     void chk_coding(bool encode, bool delayed = false);
-    bool is_coding_by_function() const;
+    bool is_coding_by_function(bool encode) const;
     const string& get_coding(bool encode) const;
   private:
     static MessageEncodingType_t get_enc_type(const Ttcn::SingleWithAttrib& enc);
diff --git a/compiler2/Value.cc b/compiler2/Value.cc
index babf951260e0eea8d6933bb7c140a6e543ed0362..cf273f8a624020f5947d76cbde328a935dc11495 100644
--- a/compiler2/Value.cc
+++ b/compiler2/Value.cc
@@ -12970,7 +12970,7 @@ error:
       break;
     }
 
-    if (!gov_last->is_coding_by_function()) {
+    if (!gov_last->is_coding_by_function(true)) {
       const string& tmp_id = get_temporary_id();
       const string& tmp_buf_id = get_temporary_id();
       const string& tmp_ref_id = get_temporary_id();
@@ -13031,7 +13031,7 @@ error:
     if (expr2.preamble)
       expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble);
 
-    if (!_type->is_coding_by_function()) {
+    if (!_type->is_coding_by_function(false)) {
       const string& tmp_id = get_temporary_id();
       const string& buffer_id = get_temporary_id();
       const string& retval_id = get_temporary_id();
@@ -13127,7 +13127,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
       v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar");
     }
 
-    if (!gov_last->is_coding_by_function()) {
+    if (!gov_last->is_coding_by_function(true)) {
       const string& tmp_id = get_temporary_id();
       const string& tmp_buf_id = get_temporary_id();
       const string& tmp_ref_id = get_temporary_id();
@@ -13205,7 +13205,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
       v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar");
     }
 
-    if (!_type->is_coding_by_function()) {
+    if (!_type->is_coding_by_function(false)) {
       const string& tmp_id = get_temporary_id();
       const string& buffer_id = get_temporary_id();
       const string& retval_id = get_temporary_id();
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 66b7eb8499e223a99a254d182649276b6b09a387..38453629180a4e1b29b828ba92afdeaf88e3576f 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -6561,9 +6561,11 @@ namespace Ttcn {
             // "untagged" on the (toplevel) input type will have no effect.
             warning("UNTAGGED encoding attribute is ignored on top-level type");
           }
-          if (Common::Type::CT_CUSTOM == encoding_type) {
+          if (Common::Type::CT_CUSTOM == encoding_type ||
+              Common::Type::CT_PER == encoding_type) {
             if (PROTOTYPE_CONVERT != prototype) {
-              error("Only `prototype(convert)' is allowed for custom encoding functions");
+              error("Only `prototype(convert)' is allowed for %s encoding functions",
+                Type::get_encoding_name(encoding_type));
             }
             else {
               // let the input type know that this is its encoding function
@@ -6580,17 +6582,25 @@ namespace Ttcn {
         }
       }
       if (output_type) {
-        if(encoding_type == Common::Type::CT_TEXT) { // TEXT encoding supports both octetstring and charstring stream types
+        if(encoding_type == Common::Type::CT_TEXT) {
+          // TEXT encoding supports bitstring, octetstring and charstring stream types
           Type *stream_type = Type::get_stream_type(encoding_type,0);
           Type *stream_type2 = Type::get_stream_type(encoding_type,1);
-          if ( (!stream_type->is_identical(output_type)) && (!stream_type2->is_identical(output_type)) ) {
-            output_type->error("The output type of %s encoding should be `%s' or `%s' "
-              "instead of `%s'", Type::get_encoding_name(encoding_type),
+          Type *stream_type3 = Type::get_stream_type(encoding_type,2);
+          if ( (!stream_type->is_identical(output_type)) &&
+               (!stream_type2->is_identical(output_type)) &&
+               (!stream_type3->is_identical(output_type))) {
+            output_type->error("The output type of %s encoding should be `%s', "
+              "`%s' or `%s' instead of `%s'", Type::get_encoding_name(encoding_type),
               stream_type->get_typename().c_str(),
               stream_type2->get_typename().c_str(),
+              stream_type3->get_typename().c_str(),
               output_type->get_typename().c_str());
           }
-        } else {
+        }
+        else if (encoding_type == Common::Type::CT_CUSTOM ||
+                 encoding_type == Common::Type::CT_PER) {
+          // custom and PER encodings only support the bitstring stream type
           Type *stream_type = Type::get_stream_type(encoding_type);
           if (!stream_type->is_identical(output_type)) {
             output_type->error("The output type of %s encoding should be `%s' "
@@ -6599,6 +6609,19 @@ namespace Ttcn {
               output_type->get_typename().c_str());
           }
         }
+        else {
+          // all other encodings support bitstring and octetstring stream types
+          Type *stream_type = Type::get_stream_type(encoding_type, 0);
+          Type *stream_type2 = Type::get_stream_type(encoding_type, 1);
+          if (!stream_type->is_identical(output_type) &&
+              !stream_type2->is_identical(output_type)) {
+            output_type->error("The output type of %s encoding should be `%s' "
+              "or '%s' instead of `%s'", Type::get_encoding_name(encoding_type),
+              stream_type->get_typename().c_str(),
+              stream_type2->get_typename().c_str(),
+              output_type->get_typename().c_str());
+          }
+        }
       }
       if (eb_list) eb_list->chk();
       chk_allowed_encode();
@@ -6608,17 +6631,25 @@ namespace Ttcn {
         error("Attribute `decode' cannot be used without `prototype'");
       }
       if (input_type) {
-        if(encoding_type == Common::Type::CT_TEXT) { // TEXT encoding supports both octetstring and charstring stream types
+        if(encoding_type == Common::Type::CT_TEXT) {
+          // TEXT encoding supports bitstring, octetstring and charstring stream types
           Type *stream_type = Type::get_stream_type(encoding_type,0);
           Type *stream_type2 = Type::get_stream_type(encoding_type,1);
-          if ( (!stream_type->is_identical(input_type)) && (!stream_type2->is_identical(input_type)) ) {
-            input_type->error("The input type of %s decoding should be `%s' or `%s' "
-              "instead of `%s'", Type::get_encoding_name(encoding_type),
+          Type *stream_type3 = Type::get_stream_type(encoding_type,2);
+          if ( (!stream_type->is_identical(input_type)) &&
+               (!stream_type2->is_identical(input_type)) &&
+               (!stream_type3->is_identical(input_type))) {
+            input_type->error("The input type of %s decoding should be `%s', "
+            "`%s' or `%s' instead of `%s'", Type::get_encoding_name(encoding_type),
               stream_type->get_typename().c_str(),
               stream_type2->get_typename().c_str(),
+              stream_type3->get_typename().c_str(),
               input_type->get_typename().c_str());
           }
-        } else {
+        }
+        else if (encoding_type == Common::Type::CT_CUSTOM ||
+                 encoding_type == Common::Type::CT_PER) {
+          // custom and PER encodings only support the bitstring stream type
           Type *stream_type = Type::get_stream_type(encoding_type);
           if (!stream_type->is_identical(input_type)) {
             input_type->error("The input type of %s decoding should be `%s' "
@@ -6627,7 +6658,19 @@ namespace Ttcn {
               input_type->get_typename().c_str());
           }
         }
-        
+        else {
+          // all other encodings support bitstring and octetstring stream types
+          Type *stream_type = Type::get_stream_type(encoding_type, 0);
+          Type *stream_type2 = Type::get_stream_type(encoding_type, 1);
+          if (!stream_type->is_identical(input_type) &&
+              !stream_type2->is_identical(input_type)) {
+            input_type->error("The input type of %s decoding should be `%s' "
+              "or `%s' instead of `%s'", Type::get_encoding_name(encoding_type),
+              stream_type->get_typename().c_str(),
+              stream_type2->get_typename().c_str(),
+              input_type->get_typename().c_str());
+          }
+        }
       }
       if (output_type && !output_type->has_encoding(encoding_type, encoding_options)) {
         if (Common::Type::CT_CUSTOM == encoding_type) {
@@ -6641,9 +6684,11 @@ namespace Ttcn {
         }
       }
       else {
-        if (Common::Type::CT_CUSTOM == encoding_type) {
+        if (Common::Type::CT_CUSTOM == encoding_type ||
+            Common::Type::CT_PER == encoding_type) {
           if (PROTOTYPE_SLIDING != prototype) {
-            error("Only `prototype(sliding)' is allowed for custom decoding functions");
+            error("Only `prototype(sliding)' is allowed for %s decoding functions",
+              Type::get_encoding_name(encoding_type));
           }
           else if (output_type) {
             // let the output type know that this is its decoding function
@@ -6863,13 +6908,25 @@ namespace Ttcn {
       result_name = 0;
     }
     // taking the result from the buffer and producing debug printout
-    str = mputprintf(str, "ttcn_buffer.get_string(%s);\n"
+    if (output_type->get_type_refd_last()->get_typetype_ttcn3() ==
+        Common::Type::T_BSTR) {
+      // cannot extract a bitstring from the buffer, use temporary octetstring
+      // and convert it to bitstring
+      str = mputprintf(str,
+        "OCTETSTRING tmp_os;\n"
+        "ttcn_buffer.get_string(tmp_os);\n"
+        "%s = oct2bit(tmp_os);\n", result_name);
+    }
+    else {
+      str = mputprintf(str, "ttcn_buffer.get_string(%s);\n", result_name);
+    }
+    str = mputprintf(str,
       "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
       "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
       "TTCN_Logger::log_event_str(\"%s(): Stream after encoding: \");\n"
       "%s.log();\n"
       "TTCN_Logger::end_event();\n"
-      "}\n", result_name, function_name, result_name);
+      "}\n", function_name, result_name);
     // returning the result stream if necessary
     if (prototype == PROTOTYPE_CONVERT) {
       if (debugger_active) {
@@ -6909,9 +6966,17 @@ namespace Ttcn {
       "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n");
     } else str = mputstr(str, "TTCN_EncDec::set_error_behavior("
       "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
+    str = mputstr(str, "TTCN_EncDec::clear_error();\n");
     // creating a buffer from the input stream
-    str = mputprintf(str, "TTCN_EncDec::clear_error();\n"
-      "TTCN_Buffer ttcn_buffer(%s);\n", first_par_name);
+    if (input_type->get_type_refd_last()->get_typetype_ttcn3() ==
+        Common::Type::T_BSTR) {
+      // cannot create a buffer from a bitstring, convert it to octetstring
+      str = mputprintf(str, "TTCN_Buffer ttcn_buffer(bit2oct(%s));\n",
+        first_par_name);
+    }
+    else {
+      str = mputprintf(str, "TTCN_Buffer ttcn_buffer(%s);\n", first_par_name);
+    }
     const char *result_name;
     if (prototype == PROTOTYPE_CONVERT) {
       // creating a local variable for the result
@@ -6949,14 +7014,25 @@ namespace Ttcn {
         "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && "
           "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n"
         "ttcn_buffer.cut();\n"
-        "%s remaining_stream;\n"
-        "ttcn_buffer.get_string(remaining_stream);\n"
+        "%s remaining_stream;\n",
+        input_type->get_genname_value(my_scope).c_str());
+      if (input_type->get_type_refd_last()->get_typetype_ttcn3() ==
+          Common::Type::T_BSTR) {
+        str = mputstr(str,
+          "OCTETSTRING tmp_os;\n"
+          "ttcn_buffer.get_string(tmp_os);\n"
+          "remaining_stream = oct2bit(tmp_os);\n");
+      }
+      else {
+        str = mputstr(str, "ttcn_buffer.get_string(remaining_stream);\n");
+      }
+      str = mputprintf(str,
         "TTCN_Logger::begin_event(TTCN_WARNING);\n"
         "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end "
           "of the stream after successful decoding: \");\n"
         "remaining_stream.log();\n"
         "TTCN_Logger::end_event();\n"
-        "}\n", input_type->get_genname_value(my_scope).c_str(), function_name);
+        "}\n", function_name);
       // closing the block and returning the appropriate result or status code
       if (prototype == PROTOTYPE_BACKTRACK) {
         if (debugger_active) {
@@ -6984,11 +7060,21 @@ namespace Ttcn {
       }
     } else {
       // result handling and debug printout for sliding decoders
-      str = mputprintf(str, "switch (TTCN_EncDec::get_last_error_type()) {\n"
+      str = mputstr(str, "switch (TTCN_EncDec::get_last_error_type()) {\n"
         "case TTCN_EncDec::ET_NONE:\n"
         // TTCN_Buffer::get_string will call OCTETSTRING::clean_up()
-        "ttcn_buffer.cut();\n"
-        "ttcn_buffer.get_string(%s);\n"
+        "ttcn_buffer.cut();\n");
+      if (input_type->get_type_refd_last()->get_typetype_ttcn3() ==
+          Common::Type::T_BSTR) {
+        str = mputprintf(str,
+          "OCTETSTRING tmp_os;\n"
+          "ttcn_buffer.get_string(tmp_os);\n"
+          "%s = oct2bit(tmp_os);\n", first_par_name);
+      }
+      else {
+        str = mputprintf(str, "ttcn_buffer.get_string(%s);\n", first_par_name);
+      }
+      str = mputprintf(str,
         "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
         "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
         "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n"
@@ -7001,7 +7087,7 @@ namespace Ttcn {
         "%sreturn 2;\n"
         "default:\n"
         "%sreturn 1;\n"
-        "}\n", first_par_name, function_name, first_par_name,
+        "}\n", function_name, first_par_name,
         debugger_active ? "ttcn3_debugger.set_return_value(\"0\");\n" : "",
         debugger_active ? "ttcn3_debugger.set_return_value(\"2\");\n" : "",
         debugger_active ? "ttcn3_debugger.set_return_value(\"1\");\n" : "");
diff --git a/compiler2/ttcn3/Attributes.cc b/compiler2/ttcn3/Attributes.cc
index 8d247e787cf88fc98543b05460d226f8e6fb50ac..54b972866d8e385bd2453ae7d2da1d696436a5aa 100644
--- a/compiler2/ttcn3/Attributes.cc
+++ b/compiler2/ttcn3/Attributes.cc
@@ -567,8 +567,8 @@ namespace Ttcn {
         if (act_attr->get_is_raw()) {
           switch (ti_type->get_typetype_ttcn3()) {
           case Type::T_BSTR:
-            if (!type->has_encoding(Type::CT_PER) && !type->has_encoding(Type::CT_RAW)) {
-              act_attr->error("A `raw' %s value was used for erroneous type `%s' which has no RAW or PER encodings.",
+            if (!type->has_encoding(Type::CT_RAW)) {
+              act_attr->error("A `raw' %s value was used for erroneous type `%s' which has no RAW encoding.",
                               ti_type->get_typename().c_str(), type->get_typename().c_str());
             }
             break;
@@ -591,7 +591,6 @@ namespace Ttcn {
         } else {
           // the two types must have at least one common encoding
           if (!((type->has_encoding(Type::CT_BER)&&ti_type->has_encoding(Type::CT_BER)) ||
-                (type->has_encoding(Type::CT_PER)&&ti_type->has_encoding(Type::CT_PER)) ||
                 (type->has_encoding(Type::CT_RAW)&&ti_type->has_encoding(Type::CT_RAW)) ||
                 (type->has_encoding(Type::CT_TEXT)&&ti_type->has_encoding(Type::CT_TEXT)) ||
                 (type->has_encoding(Type::CT_XER)&&ti_type->has_encoding(Type::CT_XER)) ||
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 1563245199747363599238f9af7f6aa8840a5478..8452c0229be9c81d4cdec46ba79079dbad0c11c0 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -9297,7 +9297,7 @@ error:
             set_params_str = mputstr(set_params_str, "}\nelse {\n");
           }
           Type::typetype_t tt = par->get_type()->get_type_refd_last()->get_typetype_ttcn3();
-          if (ve->get_dec_type()->is_coding_by_function()) {
+          if (ve->get_dec_type()->is_coding_by_function(false)) {
             set_params_str = mputstr(set_params_str, "BITSTRING buff(");
             switch (tt) {
             case Type::T_BSTR:
@@ -10041,7 +10041,7 @@ error:
               set_values_str = mputstr(set_values_str, "}\nelse {\n");
             }
             Type::typetype_t tt = redir_type->get_type_refd_last()->get_typetype_ttcn3();
-            if (member_type->is_coding_by_function()) {
+            if (member_type->is_coding_by_function(false)) {
               set_values_str = mputprintf(set_values_str, "BITSTRING buff_%d(",
                 (int)i);
               switch (tt) {
diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc
index 44a8ebcf2d1e30915677ae2ecf49004c5c53793e..0dc39effb84bef0efe83045f8fde3a3419f8d44f 100644
--- a/compiler2/ttcn3/TtcnTemplate.cc
+++ b/compiler2/ttcn3/TtcnTemplate.cc
@@ -4582,7 +4582,7 @@ compile_time:
       target_type->get_genname_value(my_scope).c_str(), class_tmp_id.c_str(),
       target_type->get_genname_template(my_scope).c_str(), class_tmp_id.c_str(),
       target_type->get_genname_value(my_scope).c_str());
-    bool dec_by_func = target_type->is_coding_by_function();
+    bool dec_by_func = target_type->is_coding_by_function(false);
     if (dec_by_func) {
       str = mputprintf(str,
         // convert the TTCN_Buffer into a bitstring
diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc
index e51f7aa230a9b19b9e2668480cfe6e4ea3d39f29..6be807e40b1493bb9d7b5627f8fdfdf972f017af 100644
--- a/compiler2/ttcn3/Ttcnstuff.cc
+++ b/compiler2/ttcn3/Ttcnstuff.cc
@@ -428,7 +428,7 @@ namespace Ttcn {
         source_type->get_typename().c_str(),
         Type::get_encoding_name(u.encdec.coding_type));
     }
-    Type *stream_type = Type::get_stream_type(u.encdec.coding_type);
+    Type *stream_type = Type::get_stream_type(u.encdec.coding_type, 1);
     if (!stream_type->is_identical(target_type)) {
       target_type->error("Target type of %s encoding should be `%s' instead "
         "of `%s'", Type::get_encoding_name(u.encdec.coding_type),
@@ -441,7 +441,7 @@ namespace Ttcn {
   void TypeMappingTarget::chk_decode(Type *source_type)
   {
     Error_Context cntxt(this, "In `decode' mapping");
-    Type *stream_type = Type::get_stream_type(u.encdec.coding_type);
+    Type *stream_type = Type::get_stream_type(u.encdec.coding_type, 1);
     if (!stream_type->is_identical(source_type)) {
       source_type->error("Source type of %s encoding should be `%s' instead "
         "of `%s'", Type::get_encoding_name(u.encdec.coding_type),
diff --git a/function_test/Semantic_Analyser/encode/Types_A.asn b/function_test/Semantic_Analyser/encode/Types_A.asn
new file mode 100644
index 0000000000000000000000000000000000000000..4a7fbdcdda566b8f3b262615211c702e4ed731bd
--- /dev/null
+++ b/function_test/Semantic_Analyser/encode/Types_A.asn
@@ -0,0 +1,42 @@
+-------------------------------------------------------------------------------
+-- Copyright (c) 2000-2016 Ericsson Telecom AB
+-- All rights reserved. This program and the accompanying materials
+-- are made available under the terms of the Eclipse Public License v1.0
+-- which accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- Contributors:
+--   Baranyi, Botond
+--
+-------------------------------------------------------------------------------
+
+Types-A
+DEFINITIONS
+
+AUTOMATIC TAGS ::=
+
+BEGIN
+IMPORTS;
+
+Int ::= INTEGER
+
+Seq ::= SEQUENCE { --//Cannot determine the encoding rules for ASN.1 type `@Types-A.Seq'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for ASN.1 type `@Types-A.Seq'. Multiple decoding external functions found with different rules//
+  num INTEGER,
+  str VisibleString
+}
+
+Set ::= SET {
+  num INTEGER,
+  str VisibleString
+}
+
+SeqOf ::= SEQUENCE OF INTEGER --//Multiple PER encoding functions set for type// //Multiple PER decoding functions set for type//
+
+SetOf ::= SET OF INTEGER
+
+Choice ::= CHOICE { --//Cannot determine the encoding rules for ASN.1 type `@Types-A.Choice'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for ASN.1 type `@Types-A.Choice'. No decoding external functions found//
+  num INTEGER,
+  str VisibleString
+}
+
+END
diff --git a/function_test/Semantic_Analyser/encode/encode_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_SE.ttcn
deleted file mode 100644
index 669a819527e33b16ed7140d063981fd272ec079d..0000000000000000000000000000000000000000
--- a/function_test/Semantic_Analyser/encode/encode_SE.ttcn
+++ /dev/null
@@ -1,33 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2000-2016 Ericsson Telecom AB
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *   Balasko, Jeno
- *   Baranyi, Botond
- *
- ******************************************************************************/
-module encode_SE {
-
-type integer AnInt with { encode "nonexistent" }; //^error\: No custom decoding function found for type//
-
-type record ARecord { //^error\: No custom decoding function found for type//
-  integer i,
-  octetstring os
-}
-
-control {
-  var ARecord x;
-  var AnInt y;
-  var bitstring bs := '110'B;
-
-  if (decvalue(bs, y) != 0) {}
-  if (decvalue(bs, x) != 0) {} 
-}
-
-} with {
-  encode "whatever"
-}
diff --git a/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn
new file mode 100644
index 0000000000000000000000000000000000000000..74ad46d660c70d02027d1378e143f3694ae7c4b8
--- /dev/null
+++ b/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn
@@ -0,0 +1,126 @@
+/******************************************************************************
+ * Copyright (c) 2000-2016 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+module encode_asn_SE { //^In TTCN-3 module//
+
+import from Types_A all;
+
+
+/* invalid PER coding functions */
+external function f_enc_list1(in Int x, out bitstring y) //^In external function definition// //Only `prototype\(convert\)' is allowed for PER encoding functions//
+  with { extension "prototype(fast) encode(PER)" }
+  
+external function f_enc_list2(in Int x) return octetstring //^In external function definition// //The output type of PER encoding should be `bitstring' instead of `octetstring'//
+  with { extension "prototype(convert) encode(PER)" }
+  
+external function f_dec_list1(in bitstring x) return Int //^In external function definition// //Only `prototype\(sliding\)' is allowed for PER decoding functions//
+  with { extension "prototype(convert) decode(PER)" }
+  
+external function f_dec_list2(in bitstring x, out Int y) //^In external function definition// //Only `prototype\(sliding\)' is allowed for PER decoding functions//
+  with { extension "prototype(fast) decode(PER)" }
+
+external function f_dec_list3(in bitstring x, out Int y) return integer //^In external function definition// //Only `prototype\(sliding\)' is allowed for PER decoding functions//
+  with { extension "prototype(backtrack) decode(PER)" }
+  
+external function f_dec_list4(inout charstring x, out Int y) return integer //^In external function definition// //The input type of PER decoding should be `bitstring' instead of `charstring'//
+  with { extension "prototype(sliding) decode(PER)" }
+
+
+/* type with multiple different built-in coding funcions */
+external function f_enc_seq1(in Seq x) return bitstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_seq2(in Seq x) return bitstring
+  with { extension "prototype(convert) encode(BER)" }
+  
+external function f_dec_seq1(inout bitstring x, out Seq y) return integer
+  with { extension "prototype(sliding) decode(BER)" }
+
+function f1() { //^In function definition//
+  var Seq x := { num := 2, str := "x" };
+  var bitstring y := encvalue(x); //^In variable definition// //^In the parameter of encvalue//
+  var integer res := decvalue(y, x);
+}
+
+external function f_dec_seq2(in bitstring x, out Seq y)
+  with { extension "prototype(fast) decode(JSON)" }
+
+
+/* type with multiple built-in encoding functions with the same coding rules, used by encvalue;
+   and multiple built-in decoding functions with different coding rules, but with no decvalue */
+external function f_enc_set1(in Set x) return bitstring
+  with { extension "prototype(convert) encode(BER)" }
+  
+external function f_enc_set2(in Set x) return bitstring
+  with { extension "prototype(convert) encode(BER)" }
+  
+external function f_dec_set1(inout bitstring x, out Set y) return integer
+  with { extension "prototype(sliding) decode(BER)" }
+
+function f2() {
+  var Set x := { num := 2, str := "x" };
+  var bitstring y := encvalue(x);
+}
+
+external function f_dec_set2(in bitstring x, out Set y)
+  with { extension "prototype(fast) decode(JSON)" }
+
+
+/* type with multiple PER coding functions */
+external function f_enc_seqof1(in SeqOf x) return bitstring
+  with { extension "prototype(convert) encode(PER)" }
+  
+external function f_enc_seqof2(in SeqOf x) return bitstring
+  with { extension "prototype(convert) encode(PER)" }
+  
+external function f_dec_seqof1(inout bitstring x, out SeqOf y) return integer
+  with { extension "prototype(sliding) decode(PER)" }
+
+function f3() {
+  var SeqOf x := { 1, 2 };
+  var bitstring y := encvalue(x);
+  var integer res := decvalue(y, x);
+}
+
+external function f_dec_seqof2(inout bitstring x, out SeqOf y) return integer
+  with { extension "prototype(sliding) decode(PER)" }
+
+
+/* type with multiple PER encoding functions, but no decvalue;
+   and both a built-in decoding function and a PER decoding function, but no decvalue */
+external function f_enc_setof1(in SetOf x) return bitstring
+  with { extension "prototype(convert) encode(PER)" }
+  
+external function f_enc_setof2(in SetOf x) return bitstring
+  with { extension "prototype(convert) encode(PER)" }
+
+external function f_dec_setof1(inout bitstring x, out SetOf y) return integer
+  with { extension "prototype(sliding) decode(PER)" }
+
+external function f_dec_setof2(inout bitstring x, out SetOf y) return integer
+  with { extension "prototype(sliding) decode(BER)" }
+
+
+/* type with both a built-in encoding function and a PER encoding function;
+   and with no decoding functions */
+function f4() {
+  var Choice x := { str := "p" };
+  var bitstring y := encvalue(x);
+  var integer res := decvalue(y, x);
+}
+
+external function f_enc_choice1(in Choice x) return bitstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_choice2(in Choice x) return bitstring
+  with { extension "prototype(convert) encode(PER)" }
+
+}
diff --git a/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn
new file mode 100644
index 0000000000000000000000000000000000000000..1de761b6d15f61ff095bcb69eaa84066fceb3a7a
--- /dev/null
+++ b/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) 2000-2016 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Balasko, Jeno
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+module encode_ttcn_SE { //^In TTCN-3 module//
+
+
+/* types with no coder functions */
+type integer AnInt with { encode "nonexistent" }; //^error\: No custom decoding function found for type//
+
+type record ARecord { //^error\: No custom decoding function found for type//
+  integer i,
+  octetstring os
+}
+
+function f1() {
+  var ARecord x;
+  var AnInt y;
+  var bitstring bs := '110'B;
+
+  if (decvalue(bs, y) != 0) {}
+  if (decvalue(bs, x) != 0) {} 
+}
+
+
+/* invalid custom coding functions */
+type record of integer AList with { encode "codec1" };
+
+external function f_enc_list1(in AList x, out bitstring y) //^In external function definition// //Only `prototype\(convert\)' is allowed for custom encoding functions//
+  with { extension "prototype(fast) encode(codec1)" }
+  
+external function f_enc_list2(in AList x) return octetstring //^In external function definition// //The output type of custom encoding should be `bitstring' instead of `octetstring'//
+  with { extension "prototype(convert) encode(codec1)" }
+  
+external function f_dec_list1(in bitstring x) return AList //^In external function definition// //Only `prototype\(sliding\)' is allowed for custom decoding functions//
+  with { extension "prototype(convert) decode(codec1)" }
+  
+external function f_dec_list2(in bitstring x, out AList y) //^In external function definition// //Only `prototype\(sliding\)' is allowed for custom decoding functions//
+  with { extension "prototype(fast) decode(codec1)" }
+
+external function f_dec_list3(in bitstring x, out AList y) return integer //^In external function definition// //Only `prototype\(sliding\)' is allowed for custom decoding functions//
+  with { extension "prototype(backtrack) decode(codec1)" }
+  
+external function f_dec_list4(inout charstring x, out AList y) return integer //^In external function definition// //The input type of custom decoding should be `bitstring' instead of `charstring'//
+  with { extension "prototype(sliding) decode(codec1)" }
+ 
+
+/* type with multiple custom coding functions */ 
+type union AUnion { //Multiple custom encoding functions set for type// //Multiple custom decoding functions set for type//
+  octetstring field
+}
+with {
+  encode "codec2"
+}
+
+external function f_enc_uni1(in AUnion x) return bitstring
+  with { extension "prototype(convert) encode(codec2)" }
+  
+external function f_enc_uni2(in AUnion x) return bitstring
+  with { extension "prototype(convert) encode(codec2)" }
+  
+external function f_dec_uni1(inout bitstring x, out AUnion y) return integer
+  with { extension "prototype(sliding) decode(codec2)" }
+
+function f2() { //^In function definition//
+  var AUnion x := { field := '1234'O };
+  var bitstring y := encvalue(x); //^In variable definition// //^In the parameter of encvalue//
+  var integer res := decvalue(y, x);
+}
+
+external function f_dec_uni2(inout bitstring x, out AUnion y) return integer
+  with { extension "prototype(sliding) decode(codec2)" }
+  
+  
+/* type with multiple custom encoding functions, but no encvalue */
+type integer AnArray[4] with { encode "codec3" }
+
+external function f_enc_arr1(in AnArray x) return bitstring
+  with { extension "prototype(convert) encode(codec3)" }
+  
+external function f_enc_arr2(in AnArray x) return bitstring
+  with { extension "prototype(convert) encode(codec3)" }
+
+
+} with {
+  encode "whatever"
+}
diff --git a/regression_test/customEncoding/Coders.cc b/regression_test/customEncoding/Coders.cc
index 139db624d873e52bb9e9d2e92beb1265a4457b39..9fc5647d3b42ca6aeaac7591b7cd63c1ce2f1bbe 100644
--- a/regression_test/customEncoding/Coders.cc
+++ b/regression_test/customEncoding/Coders.cc
@@ -98,4 +98,54 @@ INTEGER f__dec__recof(BITSTRING& b, RecOf& x)
   return 0;
 }
 
+BITSTRING f__enc__seqof(const Types::SeqOf& x)
+{
+  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
+  TTCN_Buffer buf;
+  x.encode(Types::SeqOf_descr_, buf, TTCN_EncDec::CT_JSON, false);
+  OCTETSTRING tmp;
+  buf.get_string(tmp);
+  return oct2bit(tmp);
+}
+
+INTEGER f__dec__seqof(BITSTRING& x, Types::SeqOf& y)
+{
+  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);
+  TTCN_Buffer buf(bit2oct(x));
+  y.decode(Types::SeqOf_descr_, buf, TTCN_EncDec::CT_JSON);
+  switch (TTCN_EncDec::get_last_error_type()) {
+  case TTCN_EncDec::ET_NONE: {
+    buf.cut();
+    OCTETSTRING tmp;
+    buf.get_string(tmp);
+    x = oct2bit(tmp);
+    return 0; }
+  case TTCN_EncDec::ET_INCOMPL_MSG:
+  case TTCN_EncDec::ET_LEN_ERR:
+    return 2;
+  default:
+    return 1;
+  }
+}
+
+INTEGER f__dec__choice(BITSTRING& x, Types::Choice& y)
+{
+  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);
+  TTCN_Buffer buf(bit2oct(x));
+  y.decode(Types::Choice_descr_, buf, TTCN_EncDec::CT_JSON);
+  switch (TTCN_EncDec::get_last_error_type()) {
+  case TTCN_EncDec::ET_NONE: {
+    buf.cut();
+    OCTETSTRING tmp;
+    buf.get_string(tmp);
+    x = oct2bit(tmp);
+    return 0; }
+  case TTCN_EncDec::ET_INCOMPL_MSG:
+  case TTCN_EncDec::ET_LEN_ERR:
+    return 2;
+  default:
+    return 1;
+  }
+}
+
 } // namespace Custom1
diff --git a/regression_test/customEncoding/Coders.hh b/regression_test/customEncoding/Coders.hh
index c37b61b07a571417f86c644393e29475556501a8..ba40254300d3fd9d0c9b47c77d4f3c9f1ea06480 100644
--- a/regression_test/customEncoding/Coders.hh
+++ b/regression_test/customEncoding/Coders.hh
@@ -35,6 +35,11 @@ namespace Custom1 {
 BITSTRING f__enc__recof(const RecOf& x);
 INTEGER f__dec__recof(BITSTRING& b, RecOf& x);
 
+// "PER" coder functions, using the built-in JSON codec
+extern BITSTRING f__enc__seqof(const Types::SeqOf& x);
+extern INTEGER f__dec__seqof(BITSTRING& x, Types::SeqOf& y);
+extern INTEGER f__dec__choice(BITSTRING& x, Types::Choice& y);
+
 }
 
 #endif
diff --git a/regression_test/customEncoding/Custom1.ttcn b/regression_test/customEncoding/Custom1.ttcn
index 8f253de2f4afe96fbaa3c192009fbc66da86f4b0..c26b7b56ffd3c597ebca7b9d66feb1aedacfa503 100644
--- a/regression_test/customEncoding/Custom1.ttcn
+++ b/regression_test/customEncoding/Custom1.ttcn
@@ -14,9 +14,11 @@
 // This module tests custom encoding for TTCN-3 types and encoding for ASN.1 types
 // (Encvalue and decvalue encode and decode values of TTCN-3 types using manually written
 // external functions, as long as they have the same encoding name as the value's type.
-// A similar technique is used when using encvalue or decvalue on a value of
-// and ASN.1 type: an encoding/decoding external function, of a built-in encoding type,
-// must be declared for the ASN.1 type).
+// When using encvalue or decvalue on a value of an ASN.1 type an encoding/decoding
+// external function, of a built-in encoding type, must be declared for the ASN.1 type.
+// PER encoding for ASN.1 types works similarly to custom encoding for TTCN-3 types:
+// encoding and decoding is done by manually written coders, that are declared with
+// the 'PER' encoding attribute, instead of a custom encoding attribute).
 module Custom1 {
 
 import from Custom2 all;
@@ -326,6 +328,128 @@ testcase tc_asn_decmatch() runs on CT
   }
 }
 
+// PER coder functions, these need to be implemented manually, just like custom
+// coder functions
+external function f_enc_seqof(in SeqOf x) return bitstring
+  with { extension "prototype(convert) encode(PER)" };
+  
+external function f_dec_seqof(inout bitstring x, out SeqOf y) return integer
+  with { extension "prototype(sliding) decode(PER)" };
+  
+// Test 11.
+// PER coder with encvalue and decvalue.
+testcase tc_per() runs on CT
+{
+  var SeqOf x := { 1, 2, 3 };
+  // the manually written "PER" coder for this module uses the built-in JSON coder
+  var bitstring enc_exp := oct2bit(char2oct("[1,2,3]"));
+  var SeqOf dec_exp := x;
+  
+  var bitstring enc := encvalue(x);
+  if (enc != enc_exp) {
+    setverdict(fail, "Expected: ", enc_exp, ", got: ", enc);
+  }
+  var SeqOf dec;
+  var integer res := decvalue(enc_exp, dec);
+  if (res != 0) {
+    setverdict(fail, "Failed to decode ", enc_exp);
+  }
+  if (dec != dec_exp) {
+    setverdict(fail, "Expected: ", dec_exp, ", got: ", dec);
+  }
+  setverdict(pass);
+}
+
+// Test 12.
+// The redirected parameter is decoded using the PER coder.
+// Same input value as in test 11.
+testcase tc_per_param_redirect() runs on CT
+{
+  connect(self:pt_proc, self:pt_proc);
+  var SeqOf val := { 1, 2, 3 };
+  var charstring str_fmt := "UTF-8";
+  var universal charstring val_enc := encvalue_unichar(val, str_fmt);
+  var SeqOf res;
+  pt_proc.reply(Sig: { p := val_enc });
+  timer tmr := 1.0;
+  tmr.start;
+  alt {
+    [] pt_proc.getreply(Sig: { p := val_enc }) -> param (res := @decoded(str_fmt) p) {
+      if (res != val) {
+        setverdict(fail, "Invalid decoded parameter. Expected: ", val, ", got: ", res);
+      }
+      else {
+        setverdict(pass);
+      }
+    }
+    [] pt_proc.getreply(Sig: { p := ?}) {
+      setverdict(fail, "Invalid reply received.");
+    }
+    [] tmr.timeout {
+      setverdict(fail, "Timed out.");
+    }
+  }
+}
+
+// Test 13.
+// Decoded content matching with the PER coder.
+// Same input value as in test 11.
+testcase tc_per_decmatch() runs on CT
+{
+  connect(self:pt_msg, self:pt_msg);
+  var SeqOf val := { 1, 2, 3 };
+  var Msg msg := { data := omit, list := { encvalue(val) } };
+  var SeqOf res;
+  pt_msg.send(msg);
+  timer tmr := 1.0;
+  tmr.start;
+  alt {
+    [] pt_msg.receive(Msg: { data := omit, list := { decmatch val } }) {
+      setverdict(pass);
+    }
+    [] pt_msg.receive(?) {
+      setverdict(fail, "Invalid message received or decoded content matching failed.");
+    }
+    [] tmr.timeout {
+      setverdict(fail, "Timed out.");
+    }
+  }
+}
+
+// encoder function for ASN.1 type Choice, using the built-in JSON codec
+external function f_enc_choice(in Choice x) return bitstring
+  with { extension "prototype(convert) encode(JSON)" };
+
+// PER decoder function for ASN.1 type Choice, which needs to be implemented manually
+external function f_dec_choice(inout bitstring x, out Choice y) return integer
+  with { extension "prototype(sliding) decode(PER)" };
+
+// Test 14.
+// Encoding an ASN.1 type with JSON (built-in) and decoding the same type with PER (manual).
+testcase tc_asn_mixed() runs on CT
+{
+  var Choice x := { num := 2 };
+  var bitstring enc_exp := oct2bit(char2oct("{\"num\":2}"));
+  // the manually written "PER" decoder for this module uses the built-in JSON coder,
+  // so the encoding result can safely be used as input for the decoder, and the
+  // decoding result will be the initial value
+  var Choice dec_exp := x;
+  
+  var bitstring enc := encvalue(x);
+  if (enc != enc_exp) {
+    setverdict(fail, "Expected: ", enc_exp, ", got: ", enc);
+  }
+  var Choice dec;
+  var integer res := decvalue(enc_exp, dec);
+  if (res != 0) {
+    setverdict(fail, "Failed to decode ", enc_exp);
+  }
+  if (dec != dec_exp) {
+    setverdict(fail, "Expected: ", dec_exp, ", got: ", dec);
+  }
+  setverdict(pass);
+}
+
 control {
   execute(tc_custom1());
   execute(tc_custom2());
@@ -337,6 +461,10 @@ control {
   execute(tc_asn());
   execute(tc_asn_param_redirect());
   execute(tc_asn_decmatch());
+  execute(tc_per());
+  execute(tc_per_param_redirect());
+  execute(tc_per_decmatch());
+  execute(tc_asn_mixed());
 }
 
 }
diff --git a/regression_test/customEncoding/Custom4.ttcn b/regression_test/customEncoding/Custom4.ttcn
index 9326226fe0675ac0d2457e35ffe57e075b3ae6d1..9a6bfbe50f5a180d92d7efb22f9ec0b4d251ad8b 100644
--- a/regression_test/customEncoding/Custom4.ttcn
+++ b/regression_test/customEncoding/Custom4.ttcn
@@ -19,7 +19,7 @@ import from Custom2 all;
 import from Custom3 all;
 import from Types all;
 
-// Test 11 (RT2 only).
+// Test 15 (RT2 only).
 // Using custom encoding on a decoded value redirect.
 // Same input value as in test 1.
 testcase tc_custom_value_redirect() runs on CT
@@ -50,7 +50,7 @@ testcase tc_custom_value_redirect() runs on CT
   }
 }
 
-// Test 12 (RT2 only).
+// Test 16 (RT2 only).
 // The redirected value is decoded into a value of ASN.1 type Seq.
 // Same input value as in test 8.
 testcase tc_asn_value_redirect() runs on CT
@@ -80,9 +80,40 @@ testcase tc_asn_value_redirect() runs on CT
   }
 }
 
+// Test 17 (RT2 only).
+// The redirected value is decoded using the PER coder.
+// Same input value as in test 11.
+testcase tc_per_value_redirect() runs on CT
+{
+  connect(self:pt_msg, self:pt_msg);
+  var SeqOf val := { 1, 2, 3 };
+  var Msg msg := { data := bit2oct(encvalue(val)), list := { } };
+  var SeqOf res;
+  pt_msg.send(msg);
+  timer tmr := 1.0;
+  tmr.start;
+  alt {
+    [] pt_msg.receive(msg) -> value (res := @decoded data) {
+      if (res != val) {
+        setverdict(fail, "Invalid decoded value. Expected: ", val, ", got: ", res);
+      }
+      else {
+        setverdict(pass);
+      }
+    }
+    [] pt_msg.receive(?) {
+      setverdict(fail, "Invalid message received.");
+    }
+    [] tmr.timeout {
+      setverdict(fail, "Timed out.");
+    }
+  }
+}
+
 control {
   execute(tc_custom_value_redirect());
   execute(tc_asn_value_redirect());
+  execute(tc_per_value_redirect());
 }
 
 }
diff --git a/regression_test/customEncoding/Types.asn b/regression_test/customEncoding/Types.asn
index b3ce172b1ce327e92a7272335bfa32f57070a054..19381f6f7671fb6209bb9e5a1e1e153b1b297ba7 100644
--- a/regression_test/customEncoding/Types.asn
+++ b/regression_test/customEncoding/Types.asn
@@ -23,4 +23,11 @@ Seq ::= SEQUENCE {
   str VisibleString
 }
 
+SeqOf ::= SEQUENCE OF INTEGER
+
+Choice ::= CHOICE {
+  num INTEGER,
+  str VisibleString
+}
+
 END
diff --git a/regression_test/json/Functions.ttcn b/regression_test/json/Functions.ttcn
index 888eab1e7b952de4e49ffd0c66995853aba4fe9e..2387a5737b808e5403ee54bbfed393acc1f1daf0 100644
--- a/regression_test/json/Functions.ttcn
+++ b/regression_test/json/Functions.ttcn
@@ -67,7 +67,7 @@ external function f_enc_A(in A u) return octetstring
 external function f_enc_ER(in EmptyRec u) return octetstring
   with { extension "prototype(convert)"; extension "encode(JSON)"; }
   
-external function f_enc_roi(in RoI u) return octetstring
+external function f_enc_roi(in RoI u) return bitstring
   with { extension "prototype(convert)"; extension "encode(JSON)"; }
   
 external function f_enc_rof(in RoF u) return octetstring
@@ -215,7 +215,7 @@ external function f_dec_A(in octetstring x) return A
 external function f_dec_ER(in octetstring x) return EmptyRec
   with { extension "prototype(convert)"; extension "decode(JSON)"; }
   
-external function f_dec_roi(in octetstring x) return RoI
+external function f_dec_roi(in bitstring x) return RoI
   with { extension "prototype(convert)"; extension "decode(JSON)"; }
   
 external function f_dec_rof(in octetstring x) return RoF
@@ -302,6 +302,15 @@ function f_check_encoding(in octetstring encoded, in octetstring expected) {
    }
  } with { extension "transparent"}
  
+ function f_check_encoding_bit(in bitstring encoded, in bitstring expected) {
+   log("encoded: ",encoded," expected: ",expected)
+   if(encoded == expected) {
+     setverdict(pass);
+   } else {
+      setverdict(fail, "expected:", expected,"received: ", encoded);
+   }
+ } with { extension "transparent"}
+ 
  
  
  function f_bool2verdict(in boolean b) {
diff --git a/regression_test/json/Testcases.ttcn b/regression_test/json/Testcases.ttcn
index aead2100a0c40b96a1207740eb100274f67ac05d..0e06cd7d0acf0d225e8bc6fa8c88192c42b933d0 100644
--- a/regression_test/json/Testcases.ttcn
+++ b/regression_test/json/Testcases.ttcn
@@ -367,35 +367,35 @@ testcase tc_record_empty() runs on MTC{
 
 //====== Record of===============
 
-//ROI
+//ROI (with bitstring as stream type)
 testcase tc_recordofinteger_empty() runs on MTC{
   var RoI r:={}
-  var octetstring os := char2oct("[]");
-  f_check_encoding(encoded:= f_enc_roi(r), expected := os)
+  var bitstring bs := oct2bit(char2oct("[]"));
+  f_check_encoding_bit(encoded:= f_enc_roi(r), expected := bs)
   f_bool2verdict(match(f_dec_roi(f_enc_roi(r)), r));
 }
 
 testcase tc_recordofinteger_short() runs on MTC{
   var RoI r:= { 1, 4, 5, 7, 6, 6, 4, 0 , -1 };
-  var octetstring os := char2oct("[1,4,5,7,6,6,4,0,-1]");
-  f_check_encoding(encoded:= f_enc_roi(r), expected := os)
+  var bitstring bs := oct2bit(char2oct("[1,4,5,7,6,6,4,0,-1]"));
+  f_check_encoding_bit(encoded:= f_enc_roi(r), expected := bs)
   f_bool2verdict(match(f_dec_roi(f_enc_roi(r)), r));
 }
 
 testcase tc_recordofinteger_long() runs on MTC{
   var RoI r:= {0};
-  var octetstring os := char2oct("[0");
+  var bitstring bs := oct2bit(char2oct("[0"));
   //init:
   
   for(var integer i:=1; i<50; i:=i+1) {
     r[i]:=i;
-    os := os & commao & char2oct(int2str(i));
+    bs := bs & oct2bit(commao) & oct2bit(char2oct(int2str(i)));
   }
-  os := os & char2oct("]")
+  bs := bs & oct2bit(char2oct("]"));
   log(r);
-  log(os)
+  log(bs)
   //test:
-  f_check_encoding(encoded:= f_enc_roi(r), expected := os)
+  f_check_encoding_bit(encoded:= f_enc_roi(r), expected := bs)
   f_bool2verdict(match(f_dec_roi(f_enc_roi(r)), r));
 }
 
diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc
index a88648aaab64708ff3359ed4b851a533b6c262be..a4e2530b477741e8b22beb353ba707e7dcfd28a8 100644
Binary files a/usrguide/referenceguide.doc and b/usrguide/referenceguide.doc differ